Recommended: Sing it, brah! 5 fabulous songs for developers
JW's Top 5
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 2 of 3
This could lead to unexpected results in runtime environments like an EJB container, especially since most EJB containers support optimization options to disable the serialization marshalling of method arguments for beans deployed in the same JVM. Your code's runtime behavior will then depend on this option's setting -- not a very comforting thought, is it?
As pointed out by Joshua Bloch, we must do more to ensure that serialization doesn't result in illegal Enum instances unexpectedly springing up at runtime. At a minimum, we have to add a readResolve() method and an instance field to use as the real instance ID:
public final class Enum implements java.io.Serializable
{
public static final Enum TRUE = new Enum (true);
public static final Enum FALSE = new Enum (false);
public String toString ()
{
return String.valueOf (m_value).toUpperCase ();
}
private Enum (boolean value)
{
m_value = value;
}
private Object readResolve () throws java.io.ObjectStreamException
{
return (m_value ? TRUE : FALSE);
}
private boolean m_value;
} // end of class
Here, in the readResolve() method, I check the value ID of the instance just created and replace the deserialized instance with one of the static objects.
Unfortunately, many programmers today are unaware they must implement readResolve() to perform instance substitution during serialization (this feature was not available before Java 2 either). If we don't
do this, however, we won't get any compiler or runtime errors -- the reference comparison will simply fail each time we compare
an Enum value against a deserialized Enum instance. Depending on the enumeration's size, the amount of work necessary to have a correct and serializable typesafe class
may be too much compared to the good old "typeunsafe" pattern (the standard practice of defining simple-minded sets of constants
referred to earlier), which lacks this issue.
Interestingly enough, Sun's JDK uses the typesafe enum pattern and is not consistent with making all such types Serializable: several Swing typesafe enum classes are not Serializable (for example, javax.swing.text.html.HTML.Tag), while others are (for example, java.util.logging.Level in JDK 1.4+).
Another scenario in which the typesafe enum pattern breaks completely is when the Java runtime loads the Enum class multiple times. Although this sounds obscure, it can happen more easily than you might think.
Consider an EJB invoking a method on another EJB. If the EJBs come from different deployment JAR units, different classloaders
may load them. Both deployment JARs could package the Enum class, and the particular details of the container classloader hierarchy can conspire to have both classloaders load the
Enum twice. If the two EJBs then exchange data that includes the Enum type and the data is not marshalled by means of serialization, relying on object reference identity for comparison will most
certainly fail.
Consider another possibility: a JavaServer Page (JSP) or a servlet placing data that includes Enum instances in an HTTP session. If the servlet later reloads (for example, because the JSP updates) and then attempts to compare
anything against Enum values left in the session, this will create the same effect of a class in one classloader namespace acquiring data from
a different classloader namespace.