Reputation: 2180
I'm trying to use XStream to (de)serialize a HashMap of some of my own classes in an Android app. For example, one of the classes is Word, which has the following variables:
private String word;
private boolean capitalizable;
private int useCount;
private HashMap<Character,Integer> endPunctuation;
private HashSet<String> nextWritables;
I already have the whole set up working in a standard java application, i'm just trying to wrap it all in an android UI (which works fine). Serializing works fine in Android. The problem I'm having is when I deserialize, i get the following error:
com.thoughtworks.xstream.converters.ConversionException: Cannot construct chatai.Word as it does not have a no-args constructor : Cannot construct chatai.Word as it does not have a no-args constructor
---- Debugging information ----
message : Cannot construct chatai.Word as it does not have a no-args constructor
cause-exception : com.thoughtworks.xstream.converters.reflection.ObjectAccessException
cause-message : Cannot construct chatai.Word as it does not have a no-args constructor
class : java.util.HashMap
required-type : chatai.Word
path : /map/entry/chatai.Word
line number : 1
-------------------------------
I get this error if I use any version of XStream other than 1.4.1 on my desktop application. I get the error always on my android application, no matter the verison of XStream. I'm sure that the desktop one has that issue because it's running on Java 7. I'm not sure about android. It has something to do with reflection, due to this warning when adding the xstream-1.4.1.jar:
[2011-09-07 21:06:52 - DroidBot] Dx warning: Ignoring InnerClasses attribute for an anonymous inner class
(com.thoughtworks.xstream.XStream$2) that doesn't come with an
associated EnclosingMethod attribute. This class was probably produced by a
compiler that did not target the modern .class file format. The recommended
solution is to recompile the class from source, using an up-to-date compiler
and without specifying any "-target" type options. The consequence of ignoring
this warning is that reflective operations on this class will incorrectly
indicate that it is *not* an inner class.
A quick test shows me that serializing and deserializing a String object in Android works fine. How can I get rid of that error?
Upvotes: 3
Views: 3706
Reputation: 36
Yes, this question is old, but for the curious internet researcher:
Deserialization requires xstream to construct an object and set all of its member fields to the values specified in the xml. If the object you are trying to deserialize does not have a no-arg constructor, then xstream needs help from the VM to build the object outside of the normal process of object instantiation and initialization. This help is available only in certain VMs; it is not available under the Dalvik VM when running on an Android device.
If you check the provider that is being used to deserialize your xml, you will find that on your desktop the provider is probably the Sun14ReflectionProvider, which uses special VM support to construct objects without calling their constructors. Under Android, the provider will be the PureJavaReflectionProvider, which cannot deserialize objects lacking a no-arg constructor.
XStream xstream = new XStream();
ReflectionProvider rp = xstream.getReflectionProvider();
if(null != rp)
{
System.out.println("Provider class: " + rp.getClass().getName());
if(rp instanceof Sun14ReflectionProvider)
System.out.println("Using Sun14ReflectionProvider");
else if(rp instanceof PureJavaReflectionProvider)
System.out.println("Using PureJavaReflectionProvider");
}
In summary: You cannot deserialize object lacking a no-arg constructor while running XStream in an Android environment. If you have control over the object, refactor it to have a no-arg constructor. If you do not have control over the object, you are out of luck as far as XStream is concerned.
Upvotes: 2