splain
Intelligent Error Messages for Java
February 18, 2013
Laird Nelson
splain is a small project that matches objexj Patterns against Lists of Objects to produce rich error messages.
splain has two fundamental concepts:
-
Message selector. A message selector is a key into a particular
ResourceBundle(that also identifies what baseResourceBundleit belongs to). It is represented in code by theResourceBundleKeyclass. (As it happens, a message selector may also be a simpleString.) -
Message catalog. A message catalog is an ordered list of
objexjPatterns and message selectors that certain of thosePatterns, when matched, will cause to be selected. It is represented in code by theMessageFactoryclass.
splain unites these two concepts so that when you hand it a List of Objects and a message catalog, it will return an appropriate message selector. From the message selector you can get a value out of a ResourceBundle.
Sample Message Catalog
# (Line comments like this one start with the hash (#) character.
# objexj patterns are separated from corresponding message selectors
# by a double-dash.
java.lang.String(toString() == "a")/java.lang.String(toString() == "b")$
^java.lang.String(toString() == "c")
--
com.foobar.Bizbaw/sampleKey
In the sample message catalog above, splain will attempt to match the first pattern against a user-supplied List of Objects (the pattern says that a match will occur if the List ends with a sequence of two strings, "a" and "b"). If that fails, then splain will attempt to match the next pattern against the list. If either pattern succeeds, then the corresponding message selector (com.foobar.Bizbaw/sampleKey) is used to identify a ResourceBundle and a key inside it.
This means that if we use splain to find a message selector for Arrays.asList("x", "y", "z") it will fail, but if we supply it with either Arrays.asList("c") or Arrays.asList("a", "b", "c") it will return a message selector that picks out the sampleKey key in the ResourceBundle named by the bundle name of com.foobar.Bizbaw.
Dereferencing Message Selectors
A message selector is (as mentioned previously) represented in code by the ResourceBundleKey class. It combines a bundle name with a key that should be located in a ResourceBundle with that bundle name. A ResourceBundleKey is therefore capable of returning an Object from its associated ResourceBundle.
The resulting Object, if it is a String, is treated as an MVEL template, and is interpolated using variables set in our objexj patterns!
More Realistic Examples
Matching Deep Exception Chains
javax.persistence.PersistenceException(msg = message; return true;)
--
There was a problem in the persistence layer of the application: @{msg}
Suppose you had a way to expose a Throwable and its causal chain as a List. If you handed this List to the getMessage(List) method, and if there were a PersistenceException somewhere in the causal chain, then the message selector above (in this case a simple string and not a key into some further ResourceBundle) would be interpolated as an MVEL template and its value retrieved.
Using Localized Message Selectors
Here's a message catalog that uses a localized message selector:
java.sql.SQLRecoverableException(ss = sqlState; return true;)
--
com.myco.MessageCatalog/recoverableSqlError
...and a PropertyResourceBundle properties file named com/myco/MessageCatalog.properties:
recoverableSqlError: There was a SQL error with a SQLState of @{ss}, but you can recover from it
More
For more, please see the main documentation site.