splain
Intelligent Error Messages for Java
February 18, 2013
Laird Nelson
splain
is a small project that matches objexj
Pattern
s against List
s of Object
s 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 baseResourceBundle
it belongs to). It is represented in code by theResourceBundleKey
class. (As it happens, a message selector may also be a simpleString
.) -
Message catalog. A message catalog is an ordered list of
objexj
Pattern
s and message selectors that certain of thosePattern
s, when matched, will cause to be selected. It is represented in code by theMessageFactory
class.
splain
unites these two concepts so that when you hand it a List
of Object
s 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 Object
s (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.