Frage

I need to marshal an collection List to xml but I want the user to choose which fields will be marshaled from the List's objects. Here is a better explaination of what I am trying to do.

First I have an POJO called Server

@XmlAccessorType(XmlAccessType.FIELD)
public class Server {

    @XmlElement(nillable=true)  private String vendor;
    @XmlElement(nillable=true)  private int memory;
    @XmlElement(nillable=true)  private String cpu;
//getters and setters
}

Then in my applications I have this method which is doing the marshal job. Note that this implementation is based on this Creating a Generic List Wrapper in JAXB

and MOXy's Object Graphs - Partial Models on the Fly to/from XML & JSON

    protected void marshalCollection(Object collection,OutputStream os) throws Exception {
        //The output list contains the name of the Server.class fields to be                           
        //marshaled
        List<String> output = (List<String>) getContext()
                .getHttpServletRequest().getAttribute("output");

        Class<?> cls = Class.forName("my.package.Server");

        //This list contains the Server objects to be marshaled
        List ls = (List) collection;

        JAXBContext jc = JAXBContext.newInstance(Wrapper.class, cls);
        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

        QName qName = new QName("servers");
        Wrapper wrapper = new Wrapper(ls);
        JAXBElement<Wrapper> jaxbElement = new JAXBElement<Wrapper>(qName,
                Wrapper.class, wrapper);

        ObjectGraph outputInfo = JAXBHelper.getJAXBContext(jc)
                .createObjectGraph(Wrapper.class);

        Subgraph subg = outputInfo.addSubgraph("server");

        for (String o : output) {
            subg.addAttributeNodes(o);
        }

        marshaller.setProperty(MarshallerProperties.OBJECT_GRAPH, outputInfo);
        marshaller.marshal(jaxbElement, os);

    }

Here is my Wrapper class

public class Wrapper<T> {

    @XmlAnyElement(lax=true)
    private List<T> items;

    public Wrapper() {
        items = new ArrayList<T>();
    }

    public Wrapper(List<T> items) {
        this.items = items;
    }


    public List<T> getItems() {
        return items;
    }

}

Unfortunately I get back an empty xml

<?xml version="1.0" encoding="UTF-8"?>
<servers/>

An example of what I want to get back is below

If the output list contains "memory" and "cpu" and the ls list contains two Server objects

Server[vendor=HP,memory=4096,cpu=intel]
Server[vendor=IBM,memory=2048,cpu=amd]

then the xml that I want to get back is

<?xml version="1.0" encoding="UTF-8"?>
<servers>
    <server>
        <memory>4096</memory>
        <cpu>intel</cpu>
    </server>
    <server>
        <memory>2048</memory>
        <cpu>amd</cpu>
    </server>
</servers>

Can anyone help me find what I am doing wrong? Is there any other way that I could marshal only selected fields from my Server objects in the List?

Thanks

War es hilfreich?

Lösung

You have hit a bug in how we handle Object Graphs with @XmlAnyElement(lax=true) in MOXy. You can use the following bug to track our progress on this issue.

Workaround

You could leverage JAXB with StAX for this use case. StAX will be used to write the wrapper element, and then you can marshal the individual instances of Server to it. Note how the Object Graph is created changes slightly.

    XMLOutputFactory xof = XMLOutputFactory.newFactory();
    XMLStreamWriter xsw = xof.createXMLStreamWriter(System.out);
    xsw.writeStartDocument();
    xsw.writeStartElement("servers");

    marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);

    ObjectGraph outputInfo = JAXBHelper.getJAXBContext(jc)
        .createObjectGraph(Server.class);
    for (String o : output) {
        outputInfo.addAttributeNodes(o);
    }

    marshaller.setProperty(MarshallerProperties.OBJECT_GRAPH, outputInfo);

    for(Object item : ls) {
        marshaller.marshal(item, xsw);
    }
    xsw.writeEndElement();
    xsw.writeEndDocument();
    xsw.close();
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top