Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 6277781
Votes 40
Synopsis Serialization of Enums over IIOP is broke.
Category idl:serialization
Reported Against
Release Fixed 6u11-rev(b07), 5.0u17-rev(b10) (Bug ID:2171591) , 6u14(b02) (Bug ID:2173290) , 5.0u19(b01) (Bug ID:2174419)
State 10-Fix Delivered, bug
Priority: 3-Medium
Related Bugs 6296049 , 6421053 , 6503072
Submit Date 30-MAY-2005
Description
FULL PRODUCT VERSION :
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_01-b08)
Java HotSpot(TM) Client VM (build 1.5.0_01-b08, mixed mode)


A DESCRIPTION OF THE PROBLEM :
When Enums are passed over RMI IIOP, they are not serialized/deserialized correctly.

They fail the equals() test. This is quite major.

I have an application that serializes an enumeration across a socket connection. When I read one and do an equals against one of the local Enum objects, it fails. However, enum.name().equals(deserializedEnum.name()) returns true and so does enum.getClass().equals(deserializedEnum.name()).

I am doing an import static com.foo.bar.MyEnum.* when I set my items to be serialized, I don't know if that causes a problem or not.

However, I can't reproduce the error simply. Creating a local ByteArrayOutput/Input streams works ok. This seems to be happening over a socket connection.


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
javac EnumIIOPBreakage.java
rmic -classpath . -iiop Server
java -classpath . EnumIIOPBreakage


EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
equal?                 true
classes equal? true
names equal?   true
ACTUAL -
equal?                 false
classes equal? true
names equal?   true

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.rmi.*;
import java.util.*;

import javax.rmi.*;
import javax.naming.*;

enum MyEnum { ONE, TWO, THREE };

public class EnumIIOPBreakage
{
  public static void main(String[] args)
    throws Throwable
  {
    Hashtable properties = new Hashtable();
    properties.put("java.naming.factory.initial",
                   "com.sun.jndi.cosnaming.CNCtxFactory");
    properties.put("java.naming.provider.url", "iiop://localhost:1099");

    new Server(properties);

    Context context = new InitialContext(properties);
    Object ref = context.lookup("server");
    RServer server = (RServer) PortableRemoteObject.narrow(ref, RServer.class);

    System.out.println("equal?         " +
                       MyEnum.ONE.equals(server.get(MyEnum.ONE.name())));
    System.out.println("classes equal? " +
                       MyEnum.ONE.getClass().equals(
                           server.get(MyEnum.ONE.name()).getClass()));
    System.out.println("names equal?   " +
                       MyEnum.ONE.name().equals(
                           server.get(MyEnum.ONE.name()).name()));
  }
}

class Server
  implements RServer
{
  public Server(Hashtable properties)
    throws Throwable
  {
    PortableRemoteObject.exportObject(this);

    Context context = new InitialContext(properties);
    context.rebind("server", this);
  }

  public MyEnum get(String name)
  {
    return MyEnum.valueOf(name);
  }
}


interface RServer
  extends Remote
{
  MyEnum get(String name)
    throws RemoteException;
}

---------- END SOURCE ----------
  xxxxx@xxxxx   2005-05-30 05:28:17 GMT
Work Around
N/A
Evaluation
This is interesting. Enum.equals() has reference semantic, should it preserve such reference semantic across VMs, e.g. in a RMI IIOP call?
  xxxxx@xxxxx   2005-06-01 10:26:14 GMT

Recategorizing because this CR seems primarily about the lack of support for serializing Java enum constants over RMI-IIOP.    (Note that in some circumstances the result will be deserialization failure rather than creation of an instance that doesn't behave properly-- such as if constant-specific specialization in the enum type has evolved between the sender's version and the receiver's version.)

  xxxxx@xxxxx   2005-06-06 22:44:00 GMT

This problem first requires attention by the OMG Java to IDL mapping 
RTF.  The problem is that the serialized form of a Java enum must
be interoperable across all Java ORB implementations.  Currently the
RMI-IIOP spec says nothing about Java enums, since it has not been
updated for Java SE 5.

Another problem here is that every RMI-IIOP construct must be translated
into OMG IDL so that there is a mapping in non-Java environments.
IDL does define an enum, but IDL enums are limited to simple constants,
without any possibility of methods on IDL enums (IDL enums are not
objects, unlike Java enums).

However, the IIOP marshaled form of an IDL enum is simply an unsigned
long, representing the ordinal position of the enum constant in the
definition.  This form cannot provide the kinds of binary compatibility 
that are part of the Java serialization spec.

This suggests that a more complex mapping is required.  Basically it
will be necessary to treat enums as IDL value types so that the type
information is available that will be needed to deserialize the
enum constant.

The solution that comes to mind is as follows:

1. Simply marshal enums following the standard value type rules.
2. On unmarshal, we can recognize enum constants because their
   type extends java.lang.Enum.
3. Use the information about extending Enum in simpleReadObject
   to use Enum.valueOf to find the correct enum constant.

We can't introduce a TC_ENUM as in the Java serialization code
because there is simply no place to put it in the CDR representation.

We can possibly explore this for Mustang, but I don't think any
of us on the CORBA team have time for this until Dolphin.
The almost certain necessity of dealing with this at the OMG
also makes this more difficult to fix.



  xxxxx@xxxxx   2005-06-16 18:18:47 GMT
Posted Date : 2005-06-16 18:18:47.0
Comments
  
  Include a link with my name & email   

Submitted On 12-FEB-2007
alexsmail
Why not simply to change equals method as following?
[code]
public final boolean equals(Object obj) {
 Enum other = (Enum)obj;
 if(this.ordinal==other.ordinal){
   return true;
 }
 return false;
}
[/code]	


Submitted On 01-APR-2007
I would rather implement #equals that way:

public final boolean equals(Object obj) {
   return getClass().equals(obj.getClass())
                 ? compareTo(obj.getClass().cast(obj)) == 0
                 : false;
}

Simple, and should work correctly.


Submitted On 01-APR-2007
Errata:
was:
     ? compareTo(obj.getClass().cast(obj)) == 0
should be:
     ? compareTo(getClass().cast(obj)) == 0


Submitted On 01-APR-2007
P.S.
my workaround for this to always use #compareTo instead of #equals. 
Moreover, #compareTo could be considered to be always better than #equals because it forces us to use correct Enum type. With #equals one can use incorrect Enum, it will never throw any exception or warning, the result would be always false instead.


Submitted On 01-APR-2007
I was thinking about not working #equals method, and I am scared that the Collections API might not work as expected with Enums.
That could cause major headache for many developers working with enums in distributed applications :(
And the solution seems so simple, just replace bad #equals metod as described above or maybe implement #readObject so it will always produce singletons...


Submitted On 23-MAY-2007
Why not implement the readResolve method in the Enum class and just return the correct instance there?


Submitted On 19-JUN-2007
I think it is not enough to change the #equals method, because the comparison operator == must also work correctly


Submitted On 06-AUG-2007
a little W/A could be (And I tested it) overriding the equals method with the type of the Enum, example:

enum MyEnum {
     A, B, C, D;

     public boolean equals(MyEnum obj) {
              return obj.ordinal() == this.ordinal();
     }
}

this works, but does not solve the == problem.
             


Submitted On 06-AUG-2007
btw... anybody is working on this? because when you use EJB3 and the entities has enum types it's a MUST to correct this, there's no workaround about it...
how much time will it takes? because it was reported in 2005... :s


Submitted On 27-JUN-2008
For the first several responses, how is it possible to override equals which is declared final in the Enum class?



PLEASE NOTE: JDK6 is formerly known as Project Mustang