Bendik Bendik - 3 months ago 9
Java Question

Parsing with XStream - empty tags and collections

I am using XStream to convert XML into domain objects, and have come by a problem. Omitting a few details, the XML looks like this :

<airport>
<flights>
<flight>.....</flight>
<flight>.....</flight>
<flight>.....</flight>
</flights>
</airport>


There can be 0 to N
flight
elements. The flight elements themselves contain other elements. I have created classes for airport, flights, and flight and registered them with the xstream.alias function.

xstream = new XStream();
xstream.alias("airport", AirportPojo.class);
xstream.alias("flights", FlightsPojo.class);
xstream.alias("flight", FlightPojo.class);
xstream.useAttributeFor(AirportPojo.class, "flights");
xstream.addImplicitCollection(FlightsPojo.class, "flights", FlightPojo.class);
AirportPojo airportPojo = (AirportPojo) xstream.fromXML(xml);


So, after converting, this gives me an AirportPojo object containing a FlightsPojo object, containing a collection of FlightPojo objects. However, when there are 0 flight elements it seems that the collection of FlightPojos is
null
. I would expect (and prefer) the list to be initialized but with zero elements in it. How could I accomplish this? Bear in mind that I cannot use annotations as this is a legacy project.

Answer

How about implementing a custom converter?

class FlightsConverter implements Converter {
    @Override
    public boolean canConvert(Class clazz) {
        return clazz.equals(FlightsPojo.class);
    }

    @Override
    public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
        FlightsPojo flightsPojo = new FlightsPojo();
        flightsPojo.setFlights(new ArrayList<FlightPojo>());
        while (reader.hasMoreChildren()) {
            reader.moveDown();
            FlightPojo flightPojo = (FlightPojo) context.convertAnother(flightsPojo, FlightPojo.class);
            flightsPojo.getFlights().add(flightPojo);
            System.out.println(reader.getValue());
            reader.moveUp();
        }
        return flightsPojo;
    }

    @Override
    public void marshal(Object value, HierarchicalStreamWriter writer, MarshallingContext context) {
        // todo...
    }
}

And hook it in like so:

    XStream xstream = new XStream();
    xstream.registerConverter(new FlightsConverter());
    xstream.alias("airport", AirportPojo.class);
    xstream.alias("flights", FlightsPojo.class);
    xstream.alias("flight", FlightPojo.class);
    xstream.useAttributeFor(AirportPojo.class, "flights");
    AirportPojo airportPojo = (AirportPojo) xstream.fromXML(xml);

Hope this helps ;)