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>