Zenohao Zenohao - 3 months ago 20
Java Question

Cannot construct java.util.Collection xstream

I am having troubles unmarshalling some xml using the XStream library. The related java class uses the java.util.Collection class in order to store some attributes, which I understand is a problem for XStream. However, I am unable to change the Java class to use something like ArrayList due to various reasons. Is there a way to unmarshal the xml using XStream, or should I search other libraries for a solution?

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamImplicit;
import org.testng.annotations.Test;

import java.io.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class ControllerTest {

@XStreamAlias("controllers")
public class ControllerList implements Serializable {
@XStreamImplicit(
itemFieldName = "controller"
)
private List<Controller> controllers = new ArrayList();

public ControllerList() {
}

public List<Controller> getControllers() {
return this.controllers;
}

public void setControllers(List<Controller> controllers) {
this.controllers = controllers;
}
}

@XStreamAlias("controller")
public class Controller extends BasicInfo {
@XStreamImplicit(
itemFieldName = "storageInfo"
)
private Collection<BasicInfo> storage;

public Controller() {
}

public Collection<BasicInfo> getStorage() {
return this.storage;
}

public void setStorage(Collection<BasicInfo> storage) {
this.storage = storage;
}
}

@XStreamAlias("basicinfo")
public class BasicInfo{
private String name;

public BasicInfo() {
}

public String getName() {
return this.name;
}

public void setName(String name) {
this.name = name;
}
}

@Test(groups = {"edge"})
public void testControllers() {
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><controllers><controller><storageInfo>" +
"<name>My name</name></storageInfo></controller></controllers>";
XStream stream = new XStream();
stream.processAnnotations(ControllerList.class);
InputStream in = new ByteArrayInputStream(xml.getBytes());
try {
InputStreamReader rdr = new InputStreamReader(in, "UTF-8");
ControllerList controllers = (ControllerList) stream.fromXML(rdr);
} catch (UnsupportedEncodingException e) {
}
}
}

Answer

XStream CollectionConverter does not supports java.util.Collection. So, you can try in two ways:

  1. replace Collection by List:
import java.util.List;

import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamImplicit;

@XStreamAlias("controller")
public class Controller {

    @XStreamImplicit(itemFieldName = "storageInfo")
    private List<BasicInfo> storage;

    public List<BasicInfo> getStorage() {
        return storage;
    }

    public void setStorage(final List<BasicInfo> storage) {
        this.storage = storage;
    }

}

This test should work for the first case:

@Test
public void testControllers() {
    final String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><controllers><controller><storageInfo><name>My name</name></storageInfo></controller></controllers>";
    final XStream stream = new XStream();
    stream.processAnnotations(ControllerList.class);
    final ControllerList controllers = (ControllerList) stream.fromXML(xml);

    final List<Controller> colls = controllers.getControllers();
    Assert.assertEquals(colls.size(), 1);

    final Controller coll = colls.get(0);

    final List<BasicInfo> infos = coll.getStorage();

    Assert.assertEquals(infos.size(), 1);

    final BasicInfo info = infos.get(0);

    Assert.assertEquals(info.getName(), "My name");
}
  1. Add a default implementation to java.util.Collection. This test should work:
@Test
public void testControllers() {
    final String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><controllers><controller><storageInfo><name>My name</name></storageInfo></controller></controllers>";
    final XStream stream = new XStream();
    stream.processAnnotations(ControllerList.class);
    stream.addDefaultImplementation(ArrayList.class, Collection.class);

    final ControllerList controllers = (ControllerList) stream.fromXML(xml);

    final List<Controller> colls = controllers.getControllers();
    Assert.assertEquals(colls.size(), 1);

    final Controller coll = colls.get(0);

    final Collection<BasicInfo> infos = coll.getStorage();

    Assert.assertEquals(infos.size(), 1);

    for (final BasicInfo info : infos) {
        Assert.assertEquals(info.getName(), "My name");
    }

}
Comments