Programming Tutorials Browser Tutorials Articles Struts Tutorials Hibernate Tutorials

  Tutorial: More on typesafe enums

More on typesafe enums

Tutorial Details:

Java Tip 133: More on typesafe enums
Java Tip 133: More on typesafe enums
By: By Philip Bishop
A reusable solution for serialization
any Java developers, including myself, like using the typesafe constant idiom because it provides cleaner code by removing the need to validate whether a constant value is valid or in range. I don't detail too much here, as the idiom is well documented both in JavaWorld and in several books (see Resources below).
This idiom's canonical form, shown below, uses the == operator to compare values:
public final class NumberConstants{
public static final NumberConstants ONE=new NumberConstants();
public static final NumberConstants TWO=new NumberConstants();
public static final NumberConstants THREE=new NumberConstants();
private NumberConstants(){}
}
void test(NumberConstant num){
//No need to check that the value is on range
if(num==NumberConstant.ONE){
//take some action
}
}
Using the idiom this way works well until you need to make the class serializable. Vladimir Roubtsov discusses the problem with serialization and offers an elegant solution in " Java Tip 122: Beware of Java Typesafe Enumerations ."
Roubtsov's solution uses the readResolve() method to return the correct object reference for the constant that matches the local version. That means you can continue using the convenient == operator even after one of the constants has been deserialized. This approach's only downside is that you must dirty your hands and implement readResolve() every time you need to write a new class of constants?or do you?
I'm a big fan of reusable code and created an alternate, simple solution. My approach handles the serialization problems for simple persistence and works in many distributed systems without the need to implement readResolve() in every new class of constants. The solution presented here uses an abstract class you extend as follows:
public final class NumberConstants extends AbstractConstant{
public static final NumberConstants ONE=new NumberConstants();
//etc
private NumberConstants(){}
}
The AbstractConstant class is declared (as its name suggests) abstract so it cannot be instantiated. It also implements Serializable .
The class declares two private methods writeObject() and readObject() . As usual, if these two methods are present in a Serializable class, then they will automatically invoke when the object is serialized/deserialized.
The AbstractConstant class identifies which field of the subclass is being serialized and then writes that field's name into the stream to guarantee uniqueness?since you can't have duplicate field names in a Java class. However, duplicate field names are possible within a class hierarchy; so, for this technique to work, subclasses of the AbstractConstant class must be declared final ?a rule that should be applied to all typesafe constants. Here's the code for the AbstractConstant class starting with the class definition and the writeObject() method, which writes the field name of the constant being serialized into the ObjectOutputStream :
import java.lang.reflect.Field;
public abstract class AbstractConstant
implements java.io.Serializable{
private transient String _fieldName;
private void writeObject(java.io.ObjectOutputStream out)
throws java.io.IOException {
Class clazz=getClass();
Field [] f=clazz.getDeclaredFields();
for(int i=0;Itry{
int mod=f[i].getModifiers();
if(Modifier.isStatic(mod) && Modifier.isFinal(mod)
&& Modifier.isPublic(mod)){
if(this==f[i].get(null)){
String fName=f[i].getName();
out.writeObject(fName);
}
}
}catch(IllegalAccessException ex){
throw new java.io.IOException(ex.getMessage());
}
}
}
The readObject() method then reads back the field name from the stream and assigns it to _fieldName , which is later used in the readResolve() method. The readResolve() method invokes after readObject() when an object is deserialized:
private void readObject(java.io.ObjectInputStream in)
throws java.io.IOException{
try{
_fieldName=(String)in.readObject();
}catch(ClassNotFoundException ex){
throw new java.io.IOException(ex.getMessage());
}
}
The readResolve() method then identifies the object's local static instance (by matching on the _fieldName field) and returns the corresponding object. The net result is that you can still use the == operator after deserialization because the local static constant replaces the deserialized one:
public Object readResolve()
throws java.io.ObjectStreamException{
try{
Class clazz=getClass();
Field f=clazz.getField(_fieldName);
return f.get(null);
}catch(Exception ex){
ex.printStackTrace();
throw new java.io.InvalidObjectException(
"Failed to resolve object");
}
}
}
One important point about the writeObject() method is that only a matching public static final field name is written to the stream; any additional state is ignored. So what happens when a constant has an additional state as shown below?
public final class NumberConstants extends AbstractConstant{
public static final NumberConstants ONE=new NumberConstants("1");
//etc
public String toString(){
return _rep;
}
private final String _rep;
private NumberConstants(String rep){
_rep=rep;
}
}
We are dealing with static constants, so any additional state appears preserved because readResolve() matches the constant's serialized representation with the local object reference. If for any reason a program changes state associated with a constant (i.e., a field isn't declared final ) between serializing and deserializing, then this technique fails. However, changing state associated with a constant means it's not a constant after all, and you probably shouldn't apply this idiom in the first place.
Final notes
Assuming you use typesafe constants in their canonical form, you can simply extend the AbstractConstant class and happily write and use typesafe constants knowing they will work with serialization.
This technique also works with Jini entries (that have different serialization semantics) and therefore with JavaSpaces, where a key field in an Entry is an instance of a class that extends the AbstractConstant .
Finally, keep in mind that this solution applies to simple serialization and works with many distributed Java systems, but it does not address the multiple classloader problems identified in Roubtsov's article.
This page formated for crawlers and browsers that don't support scripts and tables.
Home
EZone


 

Read Tutorial at: Click here to view the tutorial

Rate Tutorial:
More on typesafe enums

View Tutorial:
More on typesafe enums

Related Tutorials:

C#: A language alternative or just J--?, Part 2 - JavaWorld December 2000
C#: A language alternative or just J--?, Part 2 - JavaWorld December 2000
 
Interesting informations
Interesting informations
 
More on typesafe enums
More on typesafe enums
 
roots of constants classes
roots of constants classes
 
Java Development on Eclipse, Part 1
Java Development on Eclipse, Part 1 Author\'s note: In part one of a two-part series of excerpts from Eclipse\'s Chapter 2, we\'ll get down to the business of developing Java using Eclipse. We\'re going to take a look at using Eclipse for Java developm
 
Taming Tiger, Part 3
J2SE 5—code named "Tiger"—is the most significant revision to the Java language since its original inception. Tarak Modi's primary goal with his three-part series on Tiger is to familiarize readers with J2SE 5's most important additions and show how t
 
Creating Varargs in Java 1.5 Tiger
Creating Varargs in Java 1.5 Tiger In this excerpt from Chapter 5 of the book, Brett and David cover how to create and iterate over variable-length argument lists (better known as varargs), which will have you writing better, cleaner, more flexible code
 
Aspect-Oriented Annotations
Aspect-Oriented Annotations Annotations are one of the new language features in J2SE 5.0, and allow you to attach metadata onto any Java construct. Meanwhile, Aspect-Oriented Programming (AOP) is a fairly new technology that makes it easier for you to en
 
Drools
Drools is an augmented implementation of Forgy's Rete algorithm tailored for the Java language. Adapting Rete to an object-oriented interface allows for more natural expression of business rules with regards to business objects.
 
Solving the logout problem properly and elegantly
Summary Properly handling the logout process in a password-protected Web application requires more than just calling the invalidate() method on the HttpSession object because most modern browsers, with the Back and Forward buttons, allow users to go back
 
Bridging the Gap: J2SE 5.0 Annotations
Bridging the Gap: J2SE 5.0 Annotations It takes a long time for the Java community to fully absorb a major new JDK release; it seems to take about two more releases after a brand new version of the JDK before everything settles down. Application server v
 
Ease Swing development with the TableModel Free framework
This article introduces the TableModel Free (TMF) framework which eliminates the need to use TableModels with Swing JTables. The TMF framework allows for more configurable JTables by moving all of table-specific data outside of the compiled code and into
 
Memory Contention in J2EE Applications for Multiprocessor Platforms
Memory Contention in J2EE Applications for Multiprocessor Platforms. With the need for highly scalable J2EE applications in the enterprise environment, parallel processing of threads is required on multi-processor platforms. The memory requirements in th
 
Professional Java Server Programming.
An overview of the new server-side Java platform - Java 2 Enterprise Edition - as it relates to building n-tier web applications.
 
alaJSP JSP-similar processor
It is yet another servlet based preprocessor. The common idea behind that line of the products (see ColdCafe site) is splitting static HTML presentation which done by designers and dynamic proceed developed by programmers.
 
J2EE pathfinder: Implement JSP custom tags in five easy steps
JSP custom tags provide a standardized mechanism for separating presentation and business logic in a dynamic Web page, allowing page designers to focus on presentation while application developers code the back end. In this installment of J2EE pathfinder,
 

Linux Hosting Plans Proxima Web-Hosting Our basic hosting packages include support for a wide variety of web technologies, backed by instant account management with our Personal Control panel. With our guaranteed
 
Sanssouci is a Java framework for autogenerating fancy Swing-GUIs via introspection.
Sanssouci is a Java framework for autogenerating fancy Swing-GUIs via introspection which display objects directly to the user
 
Updated Hardware Certification Test Suite Available for Download
Version 2.4 of the HCTS is now available. Use it to certify your hardware on the Solaris 9 Operating System (and updates) and the Solaris 10 OS, 32-bit and 64-bit environments.
 
StatCVS offers a view into CVS repository activity
StatCVS is a handy utility for creating charts of a Concurrent Versions System (CVS) repository\'s activity.
 
Site navigation
 

 

Send your comments, Suggestions or Queries regarding this site at roseindia_net@yahoo.com.

Copyright © 2006. All rights reserved.