inigoD
inigoD

Reputation: 1741

Generic JAXB to different XMLs wrapped by same XML

I have a XML in which some common part that wrappes a specific part that can change in any way.

For example I would have to manage these 2 XML (simplified):

...
<xml>
<common>
    <data1>1</data1>
    <data2>2</data2>
</common>
<specific>
    <specific-info>
        <color>blue</color>
    </specific-info>
</specific>
</xml>
...

And this one:

...
<xml>
<common>
    <data1>33</data1>
    <data2>42</data2>
</common>
<specific>
    <another-info>
        <age>42</age>
    </another-info>
</specific>
</xml>
...

So I've inherit this code (simplified), using JAXB, that works:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {})
@XmlRootElement(name = "xml")
public class Specific{
  @XmlElement(name = "common", required = true)
  protected CommonData common;
  @XmlElement(name = "specific")
  protected SpecificInfo specificInfo;
  @XmlElement(name = "specific")
  protected AnotherInfo anotherInfo;

    // getters and setters
}

The problem is that when a new sort of info arrives I've to add new XMLElement with same name and I think that it smells... And also that they are getters an setters for each of it.

There's another way to afford this? It's a standar way to unwrap a wrapped XML with JAXB?

Upvotes: 1

Views: 179

Answers (2)

fla
fla

Reputation: 143

If I understand your need, you want to be able to get content of another elements into <specific/> ?

so maybe you can take a look to @XmlAnyElement depending on the structure your want to catch.

you might be interested in lax attribute aiming to preserve the processing of specificInfo and anotherInfo

@XmlAnyElement(lax="true")
public Object[] others;

Upvotes: 1

inigoD
inigoD

Reputation: 1741

In the way that @fisc showed me I used in my bean @XmlAnyElement in his way:

@XmlAnyElement(lax=true)
public Object[] others;

Which gets the specific part of the xml as an xml DOM object and ALSO this method to get the actual object and not a DOM representation of whatever there is in the xml:

@SuppressWarnings("unchecked")
    public <T> T getOthersParsedAs(Class<T> clazz) throws JAXBException{
        JAXBContext context = JAXBContext.newInstance(clazz);
        Unmarshaller unmarshaller = context.createUnmarshaller();
        T res = (T) unmarshaller.unmarshal((Node)others[0]);    
        if (res instanceof JAXBElement){
            res = (T)JAXBIntrospector.getValue(res); 
        }
        return res;
    }

This way I cant get them with:

Specific spec = ...
SpecificInfo info = spec.getOthersParsedAs(SpecificInfo.class);

or:

AnotherInfo info = spec.getOthersParsedAs(AnotherInfo .class);

UPDATE:

I've done a method to insert any object to that xml in that node (ugly but shows all the code in same method):

public <T> void setOthersInXML(T data) throws JAXBException, ParserConfigurationException{
        JAXBContext context = JAXBContext.newInstance(data.getClass());
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db= dbf.newDocumentBuilder();
        Document document = db.newDocument();
        Marshaller marshaller = context.createMarshaller();
        marshaller.marshal(data, document);
        others = new Object[]{document.getDocumentElement()};
    }

And is used like a setter.

Edited again

Because I found a problem: if the class haven't well defined the XMLRootElement getOthersParsedAs will return you a JAXBElement object and this could be problematic, so I've added the check to the method

Upvotes: 1

Related Questions