Posted Mon, 10 Nov 2003
I've recently run across a problem serializing "enumeration" classes over RMI method calls... here's how I resolved it.
First note that "enumeration" is in quotes for a reason, I'm not talking about the java.util.Enumeration interface. Lets say that I wanted to represent user-states in an enum, I've come to use the following pattern to accomplish this in Java in place of C/C++'s enum type:
public class UserState
{
public final static ONLINE = new UserState( "ONLINE" );
public final static OFFLINE = new UserState( OFFLINE );
public final static IDLE = new UserState( "IDLE" );
public final static AWAY = new UserState( "AWAY" );
private String name;
private UserState( String name ) {
this.name = name;
}
}
This provides me with four final static instances of a UserState in the system. I can compare them using the == operators, because UserState references will point to one of these four.
In the J2EE world, this works great within each tier; however as soon as you try to pass an object like this into another tier using a remote EJB method call, problems arise. When you pass an object over an EJB method call, the object is serialized on the caller's side, and deserialized on the receiver's side. When that object is deserialized, however, it has the same logical values, but is itself a NEW INSTANCE of the UserState class. This will fail any comparison made using the == operator to one of the original four static instances.
To get around this, what you need to do on the receiving side is check the logical value of the object passed in, and set that reference to be one of the original four static instances. To help facilitate this, I've added toString() and getInstance( String str ) methods to my enumeration class pattern:
public class UserState
{
...
public String toString() { return name; }
public UserState getInstance( String str )
{
if ( str.equals( "ONLINE" ) ) return ONLINE;
if ( str.equals( "OFFLINE" ) ) return OFFLINE;
if ( str.equals( "AWAY" ) ) return AWAY;
if ( str.equals( "IDLE" ) ) return IDLE;
return null;
}
}
So say I had a method in an EJB's Remote interface that looked like this:
public UserState getUsersState( String username ) throws RemoteException;
On the client side, what I would need to do is this:
UserState state = ejbremotereference.getUsersState( "timfanelli" ); state = UserState.getInstance( state.toString() );
This will get the user's state from the EJB instance, and then the second line reassigns the UserState reference to point to the appropriate static instance on the client. The same type of trick would be used in the Business Tier if I were to ever pass a UserState object into the EJB.
add to del.icio.us



