here are some patches for addressing the type-safe enumeration problem. I started used castor-0.9.3.9-src.zip as my base. File size is 4,850,949 bytes.
This email contains a) Two new methods for the class SourceFactory -private JMethod getReadResolveMethod() -- text is below. -public static void createTypeSafeEnumerationEqualsMethod(JClass jclass) -- text is below. b) Two lines of code (with comments) to be added to just before the end curly brace for the method processEnumerationAsNewObject() in the class SourceFactory. -- text is below. c) The attached jar (EnumTest.jar) is for the test suite. It belongs in src\tests\MasterTestSuite\xml\sourcegenerator directory. To kick it off, I ran this command line: CTFRun ./src/tests/MasterTestSuite/xml/sourcegenerator/EnumTest.jar It generates/marshals/compares a Castor-generated type-safe enum using your testing framework. d) The attached zip file (typeSafeEnumerationTest.zip) is some other test code. I couldn't figure how to put this into your test framework. I started with the source code at this link: http://www.javaworld.com/javaworld/javatips/javatip122/javatip122.zip. It shows the holes in the type-safe enum pattern. I modified this author's code to test an enum object generated from Castor with my changes. It proves that type-safe enums generated with my changes do not run into the problems mentioned in the article (http://www.javaworld.com/javaworld/javatips/jw-javatip122.html). However, I exposed some other facets of this probelm that I **WAS NOT ABLE TO FIX**. See the file output.txt for details. Look at the equals method that now is generated in a type-safe enum. Notice that there is neither 'instanceof' nor type casting. Why not? In short, because they did not behave as expected. Again, look at output.txt in this zip file for details. //############################################################## //##### start of patches for type-safe enumerations //############################################################## /** This method creates a JMethod with this signature: * <CODE>private Object readResolve () throws java.io.ObjectStreamException</CODE> * and implementing code. It presumes that the JMethod will be added to a JClass * that has the following fields: String stringValue and Hashtable _memberTable. * Why is this method important? It addresses the issues raised at * <a href="http://www.javaworld.com/javaworld/javatips/jw-javatip122.html">th is</a> url: * * @author <a href="mailto:[EMAIL PROTECTED]">Erik Ostermueller</a> */ private JMethod getReadResolveMethod() { JMethod mReadResolve = new JMethod(new JClass("java.lang.Object"), "readResolve"); mReadResolve.addException( new JClass("java.io.ObjectStreamException") ); mReadResolve.getModifiers().makePrivate(); JSourceCode jsc = mReadResolve.getSourceCode(); /** * private Object readResolve () throws java.io.ObjectStreamException { * Object obj = null; * if (stringValue != null) obj = _memberTable.get(stringValue); * if (obj == null) { * String err = "'" + stringValue + "' is not a valid '" + this.getClass().getName() + "'."; * throw new java.io.InvalidObjectException(err); * } * return obj; * } */ jsc.add("Object obj = null;"); jsc.add("if (stringValue != null) obj = _memberTable.get(stringValue);"); jsc.add("if (obj == null) {"); jsc.add(" String err = \"'\" + stringValue + \"' is not a valid '\" + this.getClass().getName() + \"'.\";"); jsc.add(" throw new java.io.InvalidObjectException(err);"); jsc.add("}"); jsc.add("return obj;"); return (mReadResolve); } /** * Create an 'equals' method that is appropriate for typeSafe enumerations on the given * JClass. * * This method addresses the issues raised * at <a href="http://www.javaworld.com/javaworld/javatips/jw-javatip122.html">th is</a> url: * The method createEqualsMethod() was used as a starting point for this code. * I intentionally did not code generate an 'instanceof' statement because * it always returned 'false' when comparing an object that had been serialized. * The same thing goes for casting a serialized object to its own type. * This consistently threw an error! * @author <a href="mailto:[EMAIL PROTECTED]">Erik Ostermueller</a> * @param jclass the Jclass in which we create the equals method */ public static void createTypeSafeEnumerationEqualsMethod(JClass jclass) { if (jclass == null) throw new IllegalArgumentException("JClass must not be null"); JField[] fields = jclass.getFields(); JMethod jMethod = new JMethod(JType.Boolean, "equals"); jMethod.setComment("Override the java.lang.Object.equals method"); jMethod.setComment("Note: hashCode() has not been overriden"); jMethod.addParameter(new JParameter(SGTypes.Object, "obj")); jclass.addMethod(jMethod); JSourceCode jsc = jMethod.getSourceCode(); jsc.add("if ( this == obj )"); jsc.indent(); jsc.add("return true;"); jsc.unindent(); jsc.add("if (this.toString().compareTo(obj.toString()) == 0)"); jsc.indent(); jsc.add("return true;"); jsc.unindent(); jsc.add("else"); jsc.indent(); jsc.add("return false;"); } //Add these two lines of code just before the end curly brace for the method processEnumerationAsNewObject(). //It is important to note that I did not make any changes to processEnumerationAsBaseType(). //It looks like this method is never invoked. /** The following two lines of code are added to address * problems with the type-safe enumeration pattern. * Without this support, comparisons of type-safe enumerations * do not work correctly. Specifically, if you serialize the * two instances of the same object, comparisons of the * unmarshalled versions of the objects will fail. * For more details, see <a href="http://www.javaworld.com/javaworld/javatips/jw-javatip122.html">th is</a> * article. */ /** * The following '.equals()' method needs to be added even if * the property file setting org.exolab.castor.builder.equalsmethod is 'false'. */ createTypeSafeEnumerationEqualsMethod(jClass); jClass.addMethod( getReadResolveMethod() ); //############################################################## //##### end of patches for type-safe enumerations //############################################################## -----Original Message----- From: Ostermueller, Erik Sent: Tuesday, April 02, 2002 2:02 PM To: [EMAIL PROTECTED] Subject: Re: [castor-dev] problems serializing type-safe enumerations Keith, If I have time, I'll try to whip up something. -----Original Message----- From: Keith Visco [mailto:[EMAIL PROTECTED]] Sent: Tuesday, April 02, 2002 1:41 PM To: [EMAIL PROTECTED] Subject: Re: [castor-dev] problems serializing type-safe enumerations Hi Erik, I read about this issue in a recent JDC Tech Tips (Java Developer Connection) newsletter from Sun. I was planning on trying to make the serialization work properly, however haven't had to much time to look into it. I was hoping this issue wouldn't come up so quickly, since I just read about the problem in the February 5th issue of the JDC Tech Tips. We'll code up a solution for people using "-type j2" option. Hopefully in the meantime you don't mind modifying your enumerations until we have a chance to do it. Or if you have a little time and want to try to fix the problem in Castor itself that would be great for all of us. Thanks, --Keith [EMAIL PROTECTED] wrote: > > Greetings, all. Thanks for such a great product. > > We are using the SourceGenerator to generate java classes based on a > schema. We are using the feature > that generates a Java type-safe enum pattern from an XML Schema > enumeration. > When we serialize those type-safe enum objects (over RMI), we are > running into problems described in this article > (http://www.javaworld.com/javaworld/javatips/jw-javatip122.html). > > In short, the == and .equals() don't work after a type-safe enumeration > object has been serialized. > Instead, one object never equals another object. > > Do you have any suggestions? One option would be to code generate a > readResolve() method as described in the article. > > Thanks again, > > Erik Ostermueller > [EMAIL PROTECTED] > ################################################### > > The following is an exerpt from this article: > > 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. > > ----------------------------------------------------------- > If you wish to unsubscribe from this mailing, send mail to > [EMAIL PROTECTED] with a subject of: > unsubscribe castor-dev ----------------------------------------------------------- If you wish to unsubscribe from this mailing, send mail to [EMAIL PROTECTED] with a subject of: unsubscribe castor-dev ----------------------------------------------------------- If you wish to unsubscribe from this mailing, send mail to [EMAIL PROTECTED] with a subject of: unsubscribe castor-dev
EnumTest.jar
Description: EnumTest.jar
typeSafeEnumerationTest.zip
Description: typeSafeEnumerationTest.zip
