I have one subtree that I would like to add to the object and make JAXB marshall the whole thing as a single tree (and with the corresponding tags). But at present, the root tag of the subtree is being replaced by the tag of another object
Unfortunately, I am not allowed to publish the source code here, so I reproduced my problem in the test code (so bear me if you find this dumb).
The idea is that I would like to derive the following structure:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <ns2:Root xmlns:ns2="urn:my:foo:bar:1.0" xmlns:ns3="urn:other:foo:bar:1.1"> <Content> <Header> <ns3:Leaf/> </Header> </Content> </ns2:Root>
but for now, all I get is:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <ns2:Root xmlns:ns2="urn:my:foo:bar:1.0" xmlns:ns3="urn:other:foo:bar:1.1"> <Content> <Header/> </Content> </ns2:Root>
I have two XSDs to create all the necessary classes, so I am fine on this side (but since these classes are generated, I cannot change them).
Here is an example of code that creates the second XML (incorrect):
package foo.bar; import java.io.OutputStream; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlType; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Document; import org.w3c.dom.Node; public class Test { private JAXBContext context; public Test() throws JAXBException { context = JAXBContext.newInstance(RootElement.class, LeafElement.class); } @XmlRootElement(name = "Root", namespace = "urn:my:foo:bar:1.0") @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "Root", propOrder = { "content" }) public static class RootElement { @XmlElement(name = "Content") protected ContentElement content; public ContentElement getContent() { return content; } public void setContent(ContentElement content) { this.content = content; } } @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "Content", propOrder = { "dummy" }) public static class ContentElement { @XmlElement(name = "Header") protected Object dummy; public Object getDummy() { return dummy; } public void setDummy(Object dummy) { this.dummy = dummy; } } @XmlRootElement(name = "Leaf", namespace = "urn:other:foo:bar:1.1") @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "Leaf") public static class LeafElement { } public Node marshal(Object obj) throws JAXBException { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); Document doc = null; try { DocumentBuilder db = dbf.newDocumentBuilder(); doc = db.newDocument(); } catch (ParserConfigurationException ex) { throw new JAXBException(ex); } Marshaller m = context.createMarshaller(); m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); m.marshal(obj, doc); return doc.getDocumentElement(); } public void marshal(Object obj, OutputStream stream) throws JAXBException { Marshaller m = context.createMarshaller(); m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); m.marshal(obj, stream); } public void test() throws JAXBException { RootElement root = new RootElement(); ContentElement content = new ContentElement(); root.setContent(content); LeafElement leaf = new LeafElement(); content.setDummy(marshal(leaf)); marshal(root, System.out); } public static void main(String[] args) throws JAXBException { new Test().test(); } }
In this code you will find 3 โsortableโ classes:
RootElementContentElement andLeafElement .
The first two classes belong to one XSD (with a given namespace), and the last from another XSD (with a different namespace), as shown in the code example.
So far, all I have found to fix this has been to create an additional class that will be set as dummy in the ContentElement and itself will hold the LeafElement so that JAXB creates the appropriate intermediate Node. But I find this solution pretty ugly, not really supported, and was hoping JAXB had a way to handle such cases.
If you need more information, or you need me to re-formulate my question, do not be shy. Itโs hard for me to explain my problem in simple words.
The limitations are as follows:
- I cannot change RootElement, ContentElement and LeafElement
- I can not use something other than jaxb