Issue Details (XML | Word | Printable)

Key: XSTR-204
Type: Bug Bug
Status: Closed Closed
Resolution: Fixed
Priority: Major Major
Assignee: Unassigned
Reporter: Bryan Coleman
Votes: 0
Watchers: 1
Operations

If you were logged in you would be able to see more operations.
XStream

deserializing Enums incorrectly

Created: 17/Mar/05 02:01 PM   Updated: 16/Jan/06 07:01 AM
Component/s: None
Affects Version/s: None
Fix Version/s: 1.1.3

JDK version and platform: 1.5.1-01 and fedora core 3


 Description  « Hide
It appears that XStream is not deserializing Enums correctly.

Here is a test for proof:

public enum MyEnum {
Test1(), Test2();

MyEnum() {

}

// public Object readResolve() { // return MyEnum.valueOf(this.name()); // }
}

MyEnum test1 = MyEnum.Test1;
System.out.println(test1.equals(xStream.fromXML(xStream.toXML(test1))));

If you run the previous two lines, it will print out false signifying that test1 is not equal to itself when ran through XStream. Now if you uncomment the readResolve method it works just fine, however, XStream should return the correct Enum. The problem exists in the ObjectInputStream. If you read the java docs on Enums in the ObjectInputStream, the ois should call the static method Enum.valueOf(Class, String).



 All   Comments   Change History      Sort Order: Ascending order - Click to sort in descending order
Bryan Coleman added a comment - 17/Mar/05 02:41 PM
Here is a solution:

You could add an EnumConverter.

public class EnumConverter extends Converter {
public boolean canConvert(Class type) { return type.isEnum(); }

public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { writer.setValue(((Enum)source).name()); }

public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { return Enum.valueOf(context.getRequiredType(), reader.getValue()); }
}


Bryan Coleman added a comment - 17/Mar/05 04:16 PM
Here is a version with support for enums with methods.

public class EnumConverter extends Converter {
public boolean canConvert(Class type) { return type.isEnum() || Enum.class.isAssignableFrom(type); }

public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { writer.setValue(((Enum)source).name()); }

public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { return Enum.valueOf(context.getRequiredType().getSuperclass(), reader.getValue()); }
}


Bryan Coleman added a comment - 18/Mar/05 08:45 AM
Yet another fix:

public class EnumConverter extends Converter {
public boolean canConvert(Class type) { return type.isEnum() || Enum.class.isAssignableFrom(type); }

public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { writer.setValue(((Enum)source).name()); }

public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { Class c = context.getRequiredType().getSuperclass() == Enum.class ? context.getRequiredType() : context.getRequiredType().getSuperclass(); return Enum.valueOf(c, reader.getValue()); }
}


Bryan Coleman added a comment - 18/Mar/05 09:35 AM
I am using version 1.1.1 with xpp3_min-1.1.3.4.I.jar

Bryan Coleman added a comment - 18/Mar/05 09:37 AM
Here is a UnitTest:

public class XStreamTest extends TestCase {
private XStream xStream;

protected void setUp() throws Exception { super.setUp(); xStream = new XStream(); xStream.registerConverter(new EnumConverter()); }

public void test() throws Exception { User user = PicapsResourceFactory.getInstance().getUserRegistry().getUser("plantfloor"); assertEquals(user, xStream.fromXML(xStream.toXML(user))); }

public void testEnum() throws Exception { assertEquals(SimpleEnum.Test1, xStream.fromXML(xStream.toXML(SimpleEnum.Test1))); assertSame(SimpleEnum.Test1, xStream.fromXML(xStream.toXML(SimpleEnum.Test1))); assertEquals(AnotherEnum.Test1, xStream.fromXML(xStream.toXML(AnotherEnum.Test1))); assertSame(AnotherEnum.Test1, xStream.fromXML(xStream.toXML(AnotherEnum.Test1))); }

private enum SimpleEnum { Test1, Test2; }

private enum AnotherEnum {
Test1() {
Object getObj() { return new Object(); }
}, Test2() {
Object getObj() { return new Object(); } }
};

abstract Object getObj();
}
}


Joe Walnes added a comment - 20/Mar/05 02:10 PM
Thanks Bryan. Enum support had already been added for XSTR-70, however this did not address the polymorphic enums. Integrating your changes finished this.

I have also added EnumMapper that ensures that the polymorphic enums don't get converted into the $1 classes, meaning the XML is cleaner and aliases can be used for enums.

I've credited your work in the code and added you to the contributors page.


Joerg Schaible added a comment - 16/Jan/06 07:01 AM
No further comment from reporter