0

I'm trying to learn XStream, and I've followed the API as well as I can understand it, but the following code snippet

List<Rectangle> rectangleArray = new ArrayList<Rectangle>();
xstream = new XStream(new DomDriver());
List<Rectangle> rectangleArray2 = new ArrayList<Rectangle>();

rectangleArray.add(new Rectangle(18,45,2,6));
String xml = xstream.toXML(rectangleArray);
System.out.println(xml);
xstream.fromXML(xml, rectangleArray2);
System.out.println("new list size: " + rectangleArray2.size());

produces output

<list>
    <java.awt.Rectangle>
    <x>18</x>
    <y>45</y>
    <width>2</width>
    <height>6</height>
    </java.awt.Rectangle>
</list>
new list size: 0

and I cannot figure out why rectangleArray2 is not now a copy of rectangleArray. Any help?

  • Maybe you have to write a custom converter. I'm not clear on that, but I'll keep reading. –  Oct 20 '12 at 02:02

1 Answers1

0

Handling List through XStream is bit trickier. To handle the list, you need to define a wrapper class to hold your list e.g.:

    public class RectangleList {

        private List<Rectangle> rectangles = new ArrayList<Rectangle>();

        public List<Rectangle> getRectangles() {
            return rectangles;
        }

        public void setRectangles(List<Rectangle> rectangles) {
            this.rectangles = rectangles;
        }
    }

Then add alias for list to RectangleList class as

      xstream.alias("list", RectangleList.class);

and register an implicit converter to manage the list as:

     xstream.addImplicitCollection(RectangleList.class, "rectangles"); 

If you want your <java.awt.Rectangle> to print as <rectangle>, register ans alias as below:

     xstream.alias("rectangle", Rectangle.class);

Now use you RectangleList class for conversion, it should work fine.

Final test code will look like:

    RectangleList recListInput = new RectangleList();
    RectangleList recListOutput = new RectangleList();
    XStream xstream = new XStream(new DomDriver());
    xstream.alias("list", RectangleList.class);
    xstream.alias("rectangle", Rectangle.class);
    xstream.addImplicitCollection(RectangleList.class, "rectangles");

    ArrayList<Rectangle> rectangleArray = new ArrayList<Rectangle>();
    rectangleArray.add(new Rectangle(18,45,2,6));
    recListInput.setRectangles(rectangleArray);
    String xml = xstream.toXML(rectangleArray);
    System.out.println(xml);
    xstream.fromXML(xml, recListOutput);
    System.out.println("new list size: " + recListOutput.getRectangles().size());

This will print output as:

    <list>
      <rectangle>
        <x>18</x>
        <y>45</y>
        <width>2</width>
        <height>6</height>
      </rectangle>
    </list>
    new list size: 1
Yogendra Singh
  • 33,927
  • 6
  • 63
  • 73
  • Thank you for this very thorough response. If I may ask a follow up: I followed your example and "RectangleList.class" is causing a NullPointerException at runtime. Any idea why? –  Oct 20 '12 at 03:09
  • Which line? I shared a working example. Did you define your attribute in RectangleList class as `private List rectangles = new ArrayList();` i.e. with initialization? – Yogendra Singh Oct 20 '12 at 03:11
  • On my machine, xstream.addImplicitCollection(RectangleList.class, "rectangles"); is throwing NullPointerException. I'm working on figuring it out. –  Oct 20 '12 at 03:15
  • 1
    You have added this line after initializing xstream i.e. after this `XStream xstream = new XStream(new DomDriver());` line, right? – Yogendra Singh Oct 20 '12 at 03:17
  • oy. That was the problem. Thanks for catching that. And thanks for a working example. I'll learn from it. This will probably help others too. –  Oct 20 '12 at 03:20