I have developed the idea a bit further. I think ResourceMessage is a better name (Message could mean too many other things). This is my contribution for you to include in the API if you want to.<br><br>Regards,<br>Rick<br>
<br><br><br><span style="font-family: courier new,monospace;">package ch.qos.cal10n;</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">import java.io.Serializable;</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">import java.util.Locale;</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">/**</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â * Holds a resource message with the locale lookup deferred until it is needed</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â * or until the locale is known. Instances are immutable so are safe to use as</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â * Exception data or share between threads. Note that the immutability is</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â * actually dependent on the supplied args themselves being immutable. If</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â * ResourceMessage instances are created that contain parameters that are</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â * mutable, the results could be unpredictable.</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â * </span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â * @author Rick Beton</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â */</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">public final class ResourceMessage implements Serializable {</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â private static final long serialVersionUID = 6660897864328889682L;</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â private final Enum<?> e;</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â private final Object[] args;</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â // cache the result of toString</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â private transient String string = null;</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â // cache the result of hashCode</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â private transient int hashcode = 0;</span><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â /**<br>Â Â Â Â * Constructs an instance.<br>Â Â Â Â * <br>Â Â Â Â * @param e<br>Â Â Â Â *Â Â Â Â Â Â Â Â Â Â Â the key for the corresponding resource.<br>
    * @param args<br>    *           any message parameters, as required.<br>    */<br>   public ResourceMessage(Enum<?> e, Object... args) {</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">      this.e = e;</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â Â Â Â if (args != null) {</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â // take defensive copy</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â this.args = new Object[args.length];</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â System.arraycopy(args, 0, this.args, 0, args.length);</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â Â Â Â } else {</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â this.args = null;</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â Â Â Â }</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â }</span><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â /**<br>Â Â Â Â * Gets the localized message from the resource bundle, using the specified<br>Â Â Â Â * locale.<br>Â Â Â Â * <br>
    * @return the message for the user<br>    */<br>   public String getLocalizedMessage(Locale locale) {</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">      final IMessageConveyor mc = new MessageConveyor(locale);</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â Â Â Â return mc.getMessage(e, args);</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â }</span><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â @Override</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â public String toString() {</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â Â Â Â if (string == null) {</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â final StringBuilder b = new StringBuilder("Message(");</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â b.append(<a href="http://e.name">e.name</a>());</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â b.append(", [");</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â if (args != null) {</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â Â Â Â String comma = "";</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â Â Â Â for (Object o : args) {</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â b.append(comma).append(o);</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â comma = ", ";</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â Â Â Â }</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â }</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â b.append("])");</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â // there may be a thread race here but the outcome is never</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â // uncertain</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â string = b.toString();</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â Â Â Â }</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â Â Â Â return string;</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â }</span><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â @Override</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â public boolean equals(Object obj) {</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â Â Â Â if (this == obj) {</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â return true;</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â Â Â Â }</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â Â Â Â if (obj.getClass() != ResourceMessage.class) {</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â return false;</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â Â Â Â }</span><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â Â Â Â final ResourceMessage other = (ResourceMessage) obj;</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â Â Â Â if (!this.e.equals(other.e)) {</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â return false;</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â Â Â Â } else if (this.args == null && other.args == null) {</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â return true;</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â Â Â Â } else if (this.args == null || other.args == null) {</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â return false;</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â Â Â Â } else if (this.args.length != other.args.length) {</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â return false;</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â Â Â Â }</span><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â Â Â Â for (int i = 0; i < args.length; i++) {</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â if (this.args[i] == null && other.args[i] == null) {</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â Â Â Â // ok</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â } else if (this.args[i] == null && other.args[i] != null) {</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â Â Â Â return false;</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â } else if (!this.args[i].equals(other.args[i])) {</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â Â Â Â return false;</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â }</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â Â Â Â }</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â Â Â Â return true;</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â }</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â @Override</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â public int hashCode() {</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â Â Â Â if (hashcode == 0) {</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â int newHashCode = 0;</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â newHashCode = e.hashCode();</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â if (args != null) {</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â Â Â Â for (Object o : args) {</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â if (o != null) {</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â newHashCode ^= o.hashCode();</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â }</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â Â Â Â }</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â }</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â // there may be a thread race here but the outcome is never</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â // uncertain</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â Â Â Â Â Â Â hashcode = newHashCode;</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â Â Â Â }</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">Â Â Â Â Â Â return hashcode;</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">Â Â Â }</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">}</span><br style="font-family: courier new,monospace;"><br>