xsdjaxbmarshallingmaven-jaxb2-plugin

Unable to generate XML using JAXB marshaller for nested Objects from different packages


**XSD1**

    <xs:complexType name="Root1">
        <xs:sequence>
            <xs:element name="Revision" type="xs:string" />
            <xs:element name="Header" type="Header" />
            <xs:element name="Body" type="SwAny" minOccurs="0" />
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="SwAny" mixed="true">
        <xs:sequence>
            <xs:any namespace="##any" processContents="skip" minOccurs="0" maxOccurs="unbounded" />
        </xs:sequence>
    </xs:complexType>



The JAVA Object for the above XSD is like below

    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "root1", propOrder = {
        "revision",
        "header",
        "body"
    })
    public class Root1
        implements Serializable
    {
    
    private final static long serialVersionUID = 1L;
    @XmlElement(name = "Revision", required = true)
    protected String revision;
    @XmlElement(name = "Header", required = true)
    protected SAA_Header header;
    @XmlElement(name = "Body")
    protected SAA_SwAny body;

-- getter and setter --
    }

    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "SwAny", propOrder = {
        "content"
    })
    public class SAA_SwAny
        implements Serializable
    {

    private final static long serialVersionUID = 1L;
    @XmlMixed
    @XmlAnyElement
    protected List<Object> content;
    }


I have another XSD which I have marshalled and generated POJO objects like below

    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "Header", propOrder = {
    "fr",
    "to"
    })
    public class Header
        implements Serializable
    {

    private final static long serialVersionUID = 1L;
    @XmlElement(name = "Fr", required = true)
    protected PartyChoice__1 fr;
    @XmlElement(name = "To", required = true)
    protected PartyChoice__1 to;

    -- getter & setter --
    }

In my class where I marshall, I create like below and marshall

    Header header = new Header();
    header.setFr(fr);
    header.setTo(to);

    Root1 **pdu** = new Root1();
    **pdu**.setRevision("rev");
    SAA_SwAny any = new SAA_SwAny();
    any.getContent().add(header);

    Marshaller mars = cfgsvc.createMarshaller(jaxbCtx, true, "UTF8", false, localPart);
    String schemaLoc = cfgsvc.findSchemaLoc(localPart);
    JAXBElement<?> elm = new JAXBElement(xmlQName, docCls, **pdu**);
    sw = new StringWriter();
    mars.marshal(elm, sw);`

When executing as per the above code, facing below exception

Caused by: com.sun.istack.SAXException2: unable to marshal type "com.test.Header" as an element because it is missing an @XmlRootElement annotation at com.sun.xml.bind.v2.runtime.XMLSerializer.reportError(XMLSerializer.java:225) ~[jaxb-impl-2.0.1.jar:2.0.1] at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeRoot(ClassBeanInfoImpl.java:274) ~[jaxb-impl-2.0.1.jar:2.0.1] at com.sun.xml.bind.v2.runtime.property.ArrayReferenceNodeProperty.serializeListBody(ArrayReferenceNodeProperty.java:78) ~[jaxb-impl-2.0.1.jar:2.0.1] at com.sun.xml.bind.v2.runtime.property.ArrayERProperty.serializeBody(ArrayERProperty.java:101) ~[jaxb-impl-2.0.1.jar:2.0.1] at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:293) ~[jaxb-impl-2.0.1.jar:2.0.1] at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:619) ~[jaxb-impl-2.0.1.jar:2.0.1] at com.sun.xml.bind.v2.runtime.property.SingleElementNodeProperty.serializeBody(SingleElementNodeProperty.java:114) ~[jaxb-impl-2.0.1.jar:2.0.1] at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:293) ~[jaxb-impl-2.0.1.jar:2.0.1] at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:619) ~[jaxb-impl-2.0.1.jar:2.0.1] at com.sun.xml.bind.v2.runtime.property.SingleElementNodeProperty.serializeBody(SingleElementNodeProperty.java:114) ~[jaxb-impl-2.0.1.jar:2.0.1] at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl$1.serializeBody(ElementBeanInfoImpl.java:98) ~[jaxb-impl-2.0.1.jar:2.0.1] at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl$1.serializeBody(ElementBeanInfoImpl.java:127) ~[jaxb-impl-2.0.1.jar:2.0.1] at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl.serializeBody(ElementBeanInfoImpl.java:244) ~[jaxb-impl-2.0.1.jar:2.0.1] at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl.serializeRoot(ElementBeanInfoImpl.java:251) ~[jaxb-impl-2.0.1.jar:2.0.1] at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl.serializeRoot(ElementBeanInfoImpl.java:33) ~[jaxb-impl-2.0.1.jar:2.0.1] at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:461) ~[jaxb-impl-2.0.1.jar:2.0.1] at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:292) ~[jaxb-impl-2.0.1.jar:2.0.1]

The workaround i did was in the header class added the below code

    **@XmlRootElement(name = "header", namespace = "head.namespace")**
    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "Header", propOrder = {
    "fr",
    "to"
    })
    public class Header
        implements Serializable
    {

    private final static long serialVersionUID = 1L;
    @XmlElement(name = "Fr", required = true)
    protected PartyChoice__1 fr;
    @XmlElement(name = "To", required = true)
    protected PartyChoice__1 to;

    -- getter & setter --
    }

now the xml marshaller works as expected and i get the below xml

<?xml version="1.0" encoding="UTF8" standalone="yes"?>
<PDU xsi:schemaLocation="...." xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <Revision>rev</Revision>
    <Body>
        <head:Hdr>
            <head:Fr>
                <head:Id>
                    <head:InstnId>
                        <head:FI>AAAASGSGXXX</head:FI>
                    </head:InstnId>
                </head:Id>
            </head:Fr>
            <head:To>
                <head:Id>
                    <head:InstnId>
                        <head:FI>AAAASGSGXXX</head:FI>
                    </head:InstnId>`your text`
                </head:Id>
            </head:To>
        </head:Hdr>
    </Body>
</PDU>

I am expecting for a solution without adding @xmlrootelement manually. Is there a way in JAXB for this ?


Solution

  • Assuming you're using some tool like former maven-jaxb2-plugin, and using jaxb api 3+ (jakarta version) you could use the following binding file to tell xjc to add @XmlRootElement on every class generated (the interesting part is the <xjc:simple/>)

    <?xml version="1.0" encoding="UTF-8"?>
    <jxb:bindings
        xmlns:jxb="https://jakarta.ee/xml/ns/jaxb"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
        jxb:extensionBindingPrefixes="xjc"
        jxb:version="3.0">
        <jxb:globalBindings>
            <xjc:simple/>
        </jxb:globalBindings>
    </jxb:bindings>
    

    Hope it'll help you.

    I said former maven-jaxb2-plugin because the plugin was renamed in latest version (check the migration guide)