Rectangle 27 0

java xStream parsing XML with duplicate tags?


@XStreamAlias("Groups")
public class GroupData {
    @XStreamAlias("Products")
    private List<Product> products = new ArrayList<>();

    @XStreamAlias("OtherProducts")
    private List<OtherProduct> otherProducts = new ArrayList<>();

    public void add(Product product) {
        getProducts().add(product);
    }

    public void add(OtherProduct otherProduct) {
        getOtherProducts().add(otherProduct);
    }

    public List<Product> getProducts() {
        return products;
    }

    public List<OtherProduct> getOtherProducts() {
        return otherProducts;
    }

}
@XStreamAlias("Product")
public class OtherProduct {

    @XStreamAlias("Id")
    private int id;

    public OtherProduct() {

    }

    public OtherProduct(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

}
@XStreamAlias("Product")
public class Product {

    @XStreamAlias("Name")
    private String name;

    public Product() {
    }

    public Product(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

    }

}
public class OtherProductConverter implements Converter {
    private ProductUnmarshaller productUnmarshaller = new ProductUnmarshaller();

    @Override
    public boolean canConvert(@SuppressWarnings("rawtypes") Class clazz) {
        return clazz.equals(OtherProduct.class);
    }

    @Override
    public void marshal(Object object, HierarchicalStreamWriter hsw, MarshallingContext mc) {
        OtherProduct otherProduct = (OtherProduct) object;
        hsw.startNode("Id");
        hsw.setValue(Integer.toString(otherProduct.getId()));
        hsw.endNode();
    }

    @Override
    public Object unmarshal(HierarchicalStreamReader hsr, UnmarshallingContext uc) {
        return productUnmarshaller.unmarshal(hsr, uc);
    }


}
public class ProductConverter implements Converter {
    private ProductUnmarshaller productUnmarshaller = new ProductUnmarshaller();

    @Override
    public boolean canConvert(@SuppressWarnings("rawtypes") Class clazz) {
        return clazz.equals(Product.class);
    }

    @Override
    public void marshal(Object object, HierarchicalStreamWriter hsw, MarshallingContext mc) {
        Product product = (Product) object;
        hsw.startNode("Name");
        hsw.setValue(product.getName());
        hsw.endNode();
    }

    @Override
    public Object unmarshal(HierarchicalStreamReader hsr, UnmarshallingContext uc) {
        return productUnmarshaller.unmarshal(hsr, uc);
    }

}
public class ProductTest {
    @Test
    public void test() {
        Product productOne = new Product("One");
        Product productTwo = new Product("Two");

        OtherProduct otherProduct1 = new OtherProduct(1);
        OtherProduct otherProduct2 = new OtherProduct(2);

        GroupData group = new GroupData();
        group.add(productOne);
        group.add(productTwo);
        group.add(otherProduct1);
        group.add(otherProduct2);

        XStream xs = new XStream();
        xs.processAnnotations(GroupData.class);
        xs.processAnnotations(OtherProduct.class);
        xs.processAnnotations(Product.class);
        xs.registerConverter(new ProductConverter());
        xs.registerConverter(new OtherProductConverter());
        String xml = xs.toXML(group);
        System.out.println(xml);
        GroupData gd = (GroupData) xs.fromXML(xml);

        for (Product product: gd.getProducts()) {
            System.out.println(product.getName());
        }

        for (OtherProduct otherProduct: gd.getOtherProducts()) {
            System.out.println(otherProduct.getId());
        }

    }

}
public class ProductUnmarshaller {

    public Object unmarshal(HierarchicalStreamReader hsr, UnmarshallingContext uc) {
        hsr.moveDown();

        String nodeName = hsr.getNodeName();
        String nodeValue = hsr.getValue();

        hsr.moveUp();

        if ("Name".equals(nodeName)) {
            return new Product(nodeValue);
        } else if ("Id".equals(nodeName)) {
            return new OtherProduct(Integer.parseInt(nodeValue));
        } else {
            return null;
        }



    }

}

And finally, a class using it all:

So, you have to teach XStream to look ahead and check for something that you know that makes them different. In that case, the inner attributes "Name" and "Id".

The marshal (Object to XML) is quite simple, the problem comes when you have to unmarshal (XML to Object) it.

The solution above shows how to solve the problem.

The solution is not straighforward.

What happens is that when XStream starts reading the XML and it finds a Product tag, it can't know for sure if it is a "Product" or "OtherProduct" object, since the tag name is the same.

You can teach XSTream how to do that writing Converters.

Note