Saturday, June 27, 2009

Java Enums Are Inherently Serializable

More than once, I have seen code such as the following (without the comments I have added to point out flaws), in which a well-intentioned Java developer has ensured that their favorite Enum explicitly declares that it is Serializable and has even provided a serialVersionUID for it.


import java.io.Serializable;

/**
* Enum example with unnecessary and ignored serialization specification
* details. The Enum is already Serializable and attempts to control its
* serialization behavior are ignored. See Section 1.12 ("Serialization of Enum
* Constants") of the "Java Object Serialization Specification Version 6.0".
*/
public enum StateEnum implements Serializable
{
ALABAMA("Alabama", "AL"),
CALIFORNIA("California", "CA"),
COLORADO("Colorado", "CO"),
IDAHO("Idaho", "ID"),
UTAH("Utah", "UT"),
WYOMING("Wyoming", "WY");

// Don't do this: Don't specify serialVersionUID for enums and don't use
// an arbitrary constant such as 42L for all versions; use serialver on Sun JDK
private static final long serialVersionUID = 42L;

private String stateName;
private String stateAbbreviation;

StateEnum(final String newStateName, final String newStateAbbreviation)
{
this.stateName = newStateName;
this.stateAbbreviation = newStateAbbreviation;
}
}


Because enums are automatically Serializable (see Javadoc API documentation for Enum), there is no need to explicitly add the "implements Serializable" clause following the enum declaration. Once this is removed, the import statement for the java.io.Serializable interface can also be removed. If you have any doubts about Enum being Serializable, run the HotSpot-provided serialver tool against your favorite enum that does not declare itself Serializable. The tool will return 0L for all enums. When a class is not Serializable, this tool returns the message "Class --yourClassNameHere-- is not Serializable." An example of this is shown in the next screen snapshot.



The fact that serialver returns 0L for the enum’s serialVersionUID indicates that the enum is indeed Serializable. The Javadoc also indicates this. A third way to prove this to yourself is to use instanceof operator as shown in the next code sample.


import java.io.Serializable;

public class UsesStateEnum
{
private StateEnum state;

public UsesStateEnum(final StateEnum newState)
{
this.state = newState;
}

public StateEnum getState()
{
return this.state;
}

public void verifyEnumIsSerializable()
{
System.out.print("StateEnum instance of Serializable? ");
System.out.println(this.state instanceof Serializable ? "yes" : "no");
}

public static void main(final String[] arguments)
{
System.out.println("Verify Enum is Serializable");
final UsesStateEnum me = new UsesStateEnum(StateEnum.COLORADO);
me.verifyEnumIsSerializable();
}
}


As mentioned above, all Enums have a serialVersionUID of 0L. Therefore, it is not necessary to specify one as is shown in the code above. In fact, when one is specified, it is ignored anyway. The example above intentionally used the hard-coded 42L used in Joshua Bloch’s Effective Java example of how not to create a serialVersionUID. As the screen snapshot below indicates, this explicitly specified value is ignored anyway:



The above screen snapshot also demonstrates an advantage of running serialver against a class to generate the serialVersionUID rather than making up an arbitrary long value such as 42L. By using the script, we get the 0L result for all enums and improve our chances of remembering that enums all have 0L for this value and don’t need it explicitly specified.

Although it does not hurt anything to unnecessarily specify that an enum implements Serializable or to even provide an ignored serialVersionUID, I prefer not to include these. One might argue that at least adding "implements Serializable" communicates the intent to have an enum be Serializable, but my feeling is that this is a fundamental part of the language since J2SE 5 and such communication should be unnecessary. When building a class that needs to be Serializable, using enum constituent pieces can be treated just the same as using Strings and primitives and the reference types corresponding to primitives.

All of the details I demonstrated and explained in this blog posting related to Enums being inherently Serializable are concisely described in two paragraphs of Section 1.12 ("Serialization of Enum Constants") of the Java Object Serialization Specification.


Additional Resources

Java Object Serialization Specification

Serialization of Enum Constants

Object Serialization: Frequently Asked Questions

Into the Mist of Serialization Myths

Flatten Your Objects: Discover the Secrets of the Java Serialization API

Java Serialization Algorithm Revealed

1 comment:

Alois Reitbauer said...

You should also mention the ability to use custom serialization using the Externalizabe interface. This can speed up Serialization Overhead as I have shown in http://blog.dynatrace.com/2008/07/01/optimizing-remoting-by-optimizing-serialization/. Additionally you gain additional flexibilty for version upgrades as you are handling serialization on your own.