Details
-
Type: Bug
-
Status: Closed
-
Resolution: Fixed
-
Affects Version/s: None
-
Fix Version/s: 1.3
-
Component/s: None
-
Labels:None
-
JDK version and platform:JDK 1.5, Linux
Description
When I have a baseclass with field annotations or I want to set the aliases by hand, the toXML method is working correctly with the derived class (taking the alias into account) but the fromXML method throws an exception.
Somehow, he's missing the information about the alias information of the fields of the base class and tries to load the element name as a class.
Example (with alias):
public class XTestBaseAlias {
String baseName;
public XTestBaseAlias( String baseName)
{ this.baseName= baseName; }}
public class XStreamTestAlias extends XTestBaseAlias {
String name;
int y;
public XStreamTestAlias( String baseName, String name, int y)
{ super( baseName); this.name= name; this.y= y; }public String toString()
{ return "XStreamTest::name="+name+" y="+y; }public static void main( String[] argv)
{ XStream xstream= new XStream( new DomDriver()); xstream.alias( "test-annotation", XStreamTestAlias.class); xstream.aliasField( "alias-name", XStreamTestAlias.class, "name"); xstream.aliasField( "alias-y", XStreamTestAlias.class, "y"); // note: the base class is used here for the field alias // otherwise the alias is not taken into account at all (also in toXML() ) xstream.aliasField( "alias-base-name", XTestBaseAlias.class, "baseName"); XStreamTestAlias test= new XStreamTestAlias( "base1", "t1", 3); String str= xstream.toXML( test); System.out.println( str); System.out.println( "\n-------------------------\n"); XStreamTestAlias test1= (XStreamTestAlias)xstream.fromXML( str); System.out.println( test1); }}
When you run the main method you will get the following output:
<test-annotation>
<alias-name>t1</alias-name>
<alias-y>3</alias-y>
<alias-base-name>base1</alias-base-name>
</test-annotation>
-------------------------
Exception in thread "main" com.thoughtworks.xstream.converters.ConversionException: alias$base$name : alias$base$name
---- Debugging information ----
required-type : com.freiheit.test.XStreamTestAlias
cause-message : alias$base$name : alias$base$name
class : com.freiheit.test.XStreamTestAlias
message : alias$base$name : alias$base$name
path : /test-annotation/alias-base-name
cause-exception : com.thoughtworks.xstream.mapper.CannotResolveClassException
-------------------------------
at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:63)
at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:45)
at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:46)
at com.thoughtworks.xstream.core.TreeUnmarshaller.start(TreeUnmarshaller.java:117)
at com.thoughtworks.xstream.core.ReferenceByXPathMarshallingStrategy.unmarshal(ReferenceByXPathMarshallingStrategy.java:29)
at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:826)
at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:813)
at com.thoughtworks.xstream.XStream.fromXML(XStream.java:761)
at com.thoughtworks.xstream.XStream.fromXML(XStream.java:753)
at com.freiheit.test.XStreamTestAlias.main(XStreamTestAlias.java:46)
Caused by: com.thoughtworks.xstream.mapper.CannotResolveClassException: alias$base$name : alias$base$name
at com.thoughtworks.xstream.mapper.DefaultMapper.realClass(DefaultMapper.java:49)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:26)
at com.thoughtworks.xstream.mapper.XStream11XmlFriendlyMapper.realClass(XStream11XmlFriendlyMapper.java:23)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:26)
at com.thoughtworks.xstream.mapper.ClassAliasingMapper.realClass(ClassAliasingMapper.java:72)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:26)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:26)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:26)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:26)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:26)
at com.thoughtworks.xstream.mapper.DynamicProxyMapper.realClass(DynamicProxyMapper.java:60)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:26)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:26)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:26)
at com.thoughtworks.xstream.mapper.ArrayMapper.realClass(ArrayMapper.java:76)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:26)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:26)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:26)
at com.thoughtworks.xstream.mapper.CachingMapper.realClass(CachingMapper.java:34)
at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.determineType(AbstractReflectionConverter.java:254)
at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:155)
at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:118)
at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:56)
... 9 more
The sources and testcases are in the attached tgz file together with a similar example with annotations.
Issue Links
- is related to
-
XSTR-279 Annotations are not inherited from parent classes
Because this bug prevents me from using XStream in a project, where I would very much like to have it used, I downloaded the sources of Version 1.2 and figured out the call stack a little bit.
I made the following, naive patch to the realMember() method of the FieldAliasingMapper class which solved the problem for me:
public String realMember(Class type, String serialized) {
{ real = (String) aliasToFieldMap.get(key( tt, serialized)); if( real == null) tt= tt.getSuperclass(); }Class tt= type;
String real = null;
while( real == null && ! tt.equals( Object.class))
if (real == null)
{ return super.realMember(type, serialized); }else
{ return real; }}