Search code examples
javajaxbjaxb2

How to get JAXB schemagen to allow multiple element names for one @XmlRootElement class


This is kind of the opposite direction of questions like No @XmlRootElement generated by JAXB. Basically I want to run schemagen and have two global elements of the same type.

<xs:element name="root1" type="tns:sameType"/>
<xs:element name="root2" type="tns:sameType"/>

I understand how to marshal things with JAXBElement but I'm at a loss on how to get the schema generated correctly. In my mind it would look something like the following snippet (@XmlRootElements is fictional).

@XmlRootElements(value = {
    @XmlRootElement(name="root1", namespace="urn:example"),
    @XmlRootElement(name="root2", namespace="urn:example")
})

Solution

  • You can use the @XmlElementDecl annotation on a class annotated with @XmlRegistry.

    ObjectFactory

    The @XmlElementDecl annotation is used when a type has multiple global elements corresponding to it. The annotation is placed on create methods on a class annotated with @XmlRegistry. When a model is generated from an XML schema this class is always called ObjectFactory.

    package forum14845035;
    
    import javax.xml.bind.JAXBElement;
    import javax.xml.bind.annotation.*;
    import javax.xml.namespace.QName;
    
    @XmlRegistry
    public class ObjectFactory {
    
        @XmlElementDecl(name="root1")
        public JAXBElement<SameType> createRoot1(SameType sameType) {
            return new JAXBElement<SameType>(new QName("urn:example", "root1"), SameType.class, sameType);
        }
    
        @XmlElementDecl(name="root2")
        public JAXBElement<SameType> createRoot2(SameType sameType) {
            return new JAXBElement<SameType>(new QName("urn:example", "root2"), SameType.class, sameType);
        }
    
    }
    

    SameType

    In this use case no annotations are required on the domain class.

    package forum14845035;
    
    public class SameType {
    
    }
    

    package-info

    We will leverage the package level @XmlSchema annotation to specify the namespace qualification for our model.

    @XmlSchema(namespace="urn:example", elementFormDefault=XmlNsForm.QUALIFIED)
    package forum14845035;
    
    import javax.xml.bind.annotation.*;
    

    Demo

    package forum14845035;
    
    import java.io.IOException;
    import javax.xml.bind.JAXBContext;
    import javax.xml.bind.SchemaOutputResolver;
    import javax.xml.transform.Result;
    import javax.xml.transform.stream.StreamResult;
    
    public class Demo {
    
        public static void main(String[] args) throws Exception {
            JAXBContext jc = JAXBContext.newInstance(SameType.class, ObjectFactory.class);
            jc.generateSchema(new SchemaOutputResolver() {
    
                @Override
                public Result createOutput(String namespaceUri,
                        String suggestedFileName) throws IOException {
                    StreamResult result = new StreamResult(System.out);
                    result.setSystemId(suggestedFileName);
                    return result;
                }
    
            });
        }
    
    }
    

    Output

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <xs:schema elementFormDefault="qualified" version="1.0" targetNamespace="urn:example" xmlns:tns="urn:example" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    
      <xs:element name="root1" type="tns:sameType"/>
    
      <xs:element name="root2" type="tns:sameType"/>
    
      <xs:complexType name="sameType">
        <xs:sequence/>
      </xs:complexType>
    
    </xs:schema>
    

    For More Information