Externalization leads to ClassCastExceptions

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

Externalization leads to ClassCastExceptions

Joseph Campolongo
I ran into some problems trying to use XStream version 1.1.2 (with and
without Xpp3) with classes that implemented the Externalizable interface.

I created two test cases to demonstrate the problem.

I suspect that I'm doing something not quite right with externalization, but
I cannot figure out what, since this code works fine to serialize &
deserialize the MyNode class.

Joseph Campolongo
Charles River Analytics

---------------------  Case #1:  No Externalization (It works)
-----------------------

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.HashSet;
import java.util.Set;

import com.thoughtworks.xstream.XStream;

public class MyNode
{
  public static void main(String[] args)
  {
    XStream xs = new XStream();
   
    MyNode m1 = new MyNode();
    for (int i = 0; i < 5; i++)
    {
      MyNode m2 = new MyNode();
      m1.addChild(m2);
      for (int j = 0; j < 5; j++)
      {
        MyNode m3 = new MyNode();
        m2.addChild(m3);
      }
    }
   
    String s = xs.toXML(m1);
   
    System.out.println(s);
   
    MyNode copy = (MyNode)xs.fromXML(s);
  }

  MyNode _parent;
  Set _children = new HashSet();
 
  public MyNode() {
  }

  public void setParent(MyNode parent) {
    if (_parent != parent) {
      _parent = parent;
      if (_parent != null) {
        _parent.addChild(this);
      }
    }
  }
 
  public void addChild(MyNode node) {
    if (!_children.contains(node)) {
      _children.add(node);
      if (node != null) {
        node.setParent(this);
      }
    }
  }
}

** This ran perfectly, and displayed the following XML

<MyNode>
  <__children>
    <MyNode>
      <__parent reference="../../.."/>
      <__children>
        <MyNode>
          <__parent reference="../../.."/>
          <__children/>
        </MyNode>
        <MyNode>
          <__parent reference="../../.."/>
          <__children/>
        </MyNode>
        <MyNode>
          <__parent reference="../../.."/>
          <__children/>
        </MyNode>
        <MyNode>
          <__parent reference="../../.."/>
          <__children/>
        </MyNode>
        <MyNode>
          <__parent reference="../../.."/>
          <__children/>
        </MyNode>
      </__children>
    </MyNode>
    <MyNode>
      <__parent reference="../../.."/>
      <__children>
        <MyNode>
          <__parent reference="../../.."/>
          <__children/>
        </MyNode>
        <MyNode>
          <__parent reference="../../.."/>
          <__children/>
        </MyNode>
        <MyNode>
          <__parent reference="../../.."/>
          <__children/>
        </MyNode>
        <MyNode>
          <__parent reference="../../.."/>
          <__children/>
        </MyNode>
        <MyNode>
          <__parent reference="../../.."/>
          <__children/>
        </MyNode>
      </__children>
    </MyNode>
    <MyNode>
      <__parent reference="../../.."/>
      <__children>
        <MyNode>
          <__parent reference="../../.."/>
          <__children/>
        </MyNode>
        <MyNode>
          <__parent reference="../../.."/>
          <__children/>
        </MyNode>
        <MyNode>
          <__parent reference="../../.."/>
          <__children/>
        </MyNode>
        <MyNode>
          <__parent reference="../../.."/>
          <__children/>
        </MyNode>
        <MyNode>
          <__parent reference="../../.."/>
          <__children/>
        </MyNode>
      </__children>
    </MyNode>
    <MyNode>
      <__parent reference="../../.."/>
      <__children>
        <MyNode>
          <__parent reference="../../.."/>
          <__children/>
        </MyNode>
        <MyNode>
          <__parent reference="../../.."/>
          <__children/>
        </MyNode>
        <MyNode>
          <__parent reference="../../.."/>
          <__children/>
        </MyNode>
        <MyNode>
          <__parent reference="../../.."/>
          <__children/>
        </MyNode>
        <MyNode>
          <__parent reference="../../.."/>
          <__children/>
        </MyNode>
      </__children>
    </MyNode>
    <MyNode>
      <__parent reference="../../.."/>
      <__children>
        <MyNode>
          <__parent reference="../../.."/>
          <__children/>
        </MyNode>
        <MyNode>
          <__parent reference="../../.."/>
          <__children/>
        </MyNode>
        <MyNode>
          <__parent reference="../../.."/>
          <__children/>
        </MyNode>
        <MyNode>
          <__parent reference="../../.."/>
          <__children/>
        </MyNode>
        <MyNode>
          <__parent reference="../../.."/>
          <__children/>
        </MyNode>
      </__children>
    </MyNode>
  </__children>
</MyNode>


--------- Case #2:  Externalization with individual Serialization of
properties --------

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.HashSet;
import java.util.Set;

import com.thoughtworks.xstream.XStream;

public class MyNode implements Externalizable
{
  /**
   * @param args
   */
  public static void main(String[] args)
  {
    XStream xs = new XStream();
   
    MyNode m1 = new MyNode();
    for (int i = 0; i < 5; i++)
    {
      MyNode m2 = new MyNode();
      m1.addChild(m2);
      for (int j = 0; j < 5; j++)
      {
        MyNode m3 = new MyNode();
        m2.addChild(m3);
      }
    }
   
    String s = xs.toXML(m1);
   
    System.out.println(s);
   
    MyNode copy = (MyNode)xs.fromXML(s);
  }

  MyNode _parent;
  Set _children = new HashSet();
 
  public MyNode() {
  }

  public void setParent(MyNode parent) {
    if (_parent != parent) {
      _parent = parent;
      if (_parent != null) {
        _parent.addChild(this);
      }
    }
  }
 
  public void addChild(MyNode node) {
    if (!_children.contains(node)) {
      _children.add(node);
      if (node != null) {
        node.setParent(this);
      }
    }
  }
 
  public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException
  {
    _parent = (MyNode)in.readObject();
    _children = (Set)in.readObject();
  }

  public void writeExternal(ObjectOutput out) throws IOException
  {
    out.writeObject(_parent);
    out.writeObject(_children);
  }
}

** This code produced the following XML with the following exception

<MyNode>
  <null/>
  <set>
    <MyNode>
      <MyNode reference="../../.."/>
      <set>
        <MyNode>
          <MyNode reference="../../.."/>
          <set/>
        </MyNode>
        <MyNode>
          <MyNode reference="../../.."/>
          <set/>
        </MyNode>
        <MyNode>
          <MyNode reference="../../.."/>
          <set/>
        </MyNode>
        <MyNode>
          <MyNode reference="../../.."/>
          <set/>
        </MyNode>
        <MyNode>
          <MyNode reference="../../.."/>
          <set/>
        </MyNode>
      </set>
    </MyNode>
    <MyNode>
      <MyNode reference="../../.."/>
      <set>
        <MyNode>
          <MyNode reference="../../.."/>
          <set/>
        </MyNode>
        <MyNode>
          <MyNode reference="../../.."/>
          <set/>
        </MyNode>
        <MyNode>
          <MyNode reference="../../.."/>
          <set/>
        </MyNode>
        <MyNode>
          <MyNode reference="../../.."/>
          <set/>
        </MyNode>
        <MyNode>
          <MyNode reference="../../.."/>
          <set/>
        </MyNode>
      </set>
    </MyNode>
    <MyNode>
      <MyNode reference="../../.."/>
      <set>
        <MyNode>
          <MyNode reference="../../.."/>
          <set/>
        </MyNode>
        <MyNode>
          <MyNode reference="../../.."/>
          <set/>
        </MyNode>
        <MyNode>
          <MyNode reference="../../.."/>
          <set/>
        </MyNode>
        <MyNode>
          <MyNode reference="../../.."/>
          <set/>
        </MyNode>
        <MyNode>
          <MyNode reference="../../.."/>
          <set/>
        </MyNode>
      </set>
    </MyNode>
    <MyNode>
      <MyNode reference="../../.."/>
      <set>
        <MyNode>
          <MyNode reference="../../.."/>
          <set/>
        </MyNode>
        <MyNode>
          <MyNode reference="../../.."/>
          <set/>
        </MyNode>
        <MyNode>
          <MyNode reference="../../.."/>
          <set/>
        </MyNode>
        <MyNode>
          <MyNode reference="../../.."/>
          <set/>
        </MyNode>
        <MyNode>
          <MyNode reference="../../.."/>
          <set/>
        </MyNode>
      </set>
    </MyNode>
    <MyNode>
      <MyNode reference="../../.."/>
      <set>
        <MyNode>
          <MyNode reference="../../.."/>
          <set/>
        </MyNode>
        <MyNode>
          <MyNode reference="../../.."/>
          <set/>
        </MyNode>
        <MyNode>
          <MyNode reference="../../.."/>
          <set/>
        </MyNode>
        <MyNode>
          <MyNode reference="../../.."/>
          <set/>
        </MyNode>
        <MyNode>
          <MyNode reference="../../.."/>
          <set/>
        </MyNode>
      </set>
    </MyNode>
  </set>
</MyNode>
com.thoughtworks.xstream.converters.ConversionException: null
---- Debugging information ----
required-type       : MyNode
cause-message       : null
class               : MyNode
line number         : 5
path                : /MyNode/set/MyNode
cause-exception     : java.lang.ClassCastException
-------------------------------
        at
com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshall
er.java:45)
        at
com.thoughtworks.xstream.core.ReferenceByXPathUnmarshaller.convertAnother(Re
ferenceByXPathUnmarshaller.java:39)
        at
com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter.
readItem(AbstractCollectionConverter.java:82)
        at
com.thoughtworks.xstream.converters.collections.CollectionConverter.populate
Collection(CollectionConverter.java:60)
        at
com.thoughtworks.xstream.converters.collections.CollectionConverter.unmarsha
l(CollectionConverter.java:53)
        at
com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshall
er.java:38)
        at
com.thoughtworks.xstream.core.ReferenceByXPathUnmarshaller.convertAnother(Re
ferenceByXPathUnmarshaller.java:39)
        at
com.thoughtworks.xstream.converters.reflection.ExternalizableConverter$2.rea
dFromStream(ExternalizableConverter.java:84)
        at
com.thoughtworks.xstream.core.util.CustomObjectInputStream.readObjectOverrid
e(CustomObjectInputStream.java:66)
        at java.io.ObjectInputStream.readObject(Unknown Source)
        at MyNode.readExternal(MyNode.java:65)
        at
com.thoughtworks.xstream.converters.reflection.ExternalizableConverter.unmar
shal(ExternalizableConverter.java:106)
        at
com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshall
er.java:38)
        at
com.thoughtworks.xstream.core.ReferenceByXPathUnmarshaller.convertAnother(Re
ferenceByXPathUnmarshaller.java:39)
        at
com.thoughtworks.xstream.core.TreeUnmarshaller.start(TreeUnmarshaller.java:9
9)
        at
com.thoughtworks.xstream.core.ReferenceByXPathMarshallingStrategy.unmarshal(
ReferenceByXPathMarshallingStrategy.java:12)
        at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:521)
        at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:509)
        at com.thoughtworks.xstream.XStream.fromXML(XStream.java:475)
        at com.thoughtworks.xstream.XStream.fromXML(XStream.java:468)
        at MyNode.main(MyNode.java:35)
Caused by: java.lang.ClassCastException
        at MyNode.readExternal(MyNode.java:64)
        at
com.thoughtworks.xstream.converters.reflection.ExternalizableConverter.unmar
shal(ExternalizableConverter.java:106)
        at
com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshall
er.java:38)
        ... 20 more
Exception in thread "main"

** The ClassCastException is caused by the line

  _parent = (MyNode)in.readObject();

** in.readObject() is returning a Class object (Class MyNode), which is
being read from the ReferenceByXPathUnmarshaller's 'value' map.  Why this is
a Class object instead of the actual instance, I don't know.


Reply | Threaded
Open this post in threaded view
|

Re: Externalization leads to ClassCastExceptions

Jörg Schaible-2
Hi Joseph,

Joseph Campolongo wrote:

> I ran into some problems trying to use XStream version 1.1.2 (with and
> without Xpp3) with classes that implemented the Externalizable interface.

[snip]

> com.thoughtworks.xstream.converters.ConversionException: null
> ---- Debugging information ----
> required-type       : MyNode
> cause-message       : null
> class               : MyNode
> line number         : 5
> path                : /MyNode/set/MyNode
> cause-exception     : java.lang.ClassCastException
> -------------------------------
> at
>
com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshall
> er.java:45)

[snip]

> ** The ClassCastException is caused by the line
>
>   _parent = (MyNode)in.readObject();
>
> ** in.readObject() is returning a Class object (Class MyNode), which is
> being read from the ReferenceByXPathUnmarshaller's 'value' map.  Why this
> is a Class object instead of the actual instance, I don't know.

This was a simple bug in the converter for Externalizable objects. Fix
already committed to the trunk (see XSTR-263).

- Jörg