Search code examples
javaxmljaxbmarshallingqnames

Namespace defined through QName is not shown in xsi:type attribute leading to validation failure


Here is my problem.

I have an xsd in which the need of polymorphism is answered by the use of xs:extension as follows:

<xs:complexType name="abstract_item" abstract="true">
    <xs:sequence>
        <xs:element name="blabla" type="xs:string" minOccurs="1" maxOccurs="1">
    </xs:sequence>  
</xs:complexType>

<xs:complexType name="itemA">
    <xs:complexContent>
        <xs:extension base="abstract_item">
            <xs:sequence>
                <xs:element name="blabla1" type="xs:string" minOccurs="0" maxOccurs="1">
            </xs:sequence>
        </xs:extension>
    </xs:complexContent>
</xs:complexType>

<xs:complexType name="itemB">
    <xs:complexContent>
        <xs:extension base="abstract_item">
            <xs:sequence>
                <xs:element name="blabla2" type="xs:date" minOccurs="0" maxOccurs="1">
            </xs:sequence>
        </xs:extension>
    </xs:complexContent>
</xs:complexType>

The JaxB classes appear to be correctly generated using xjc (two classes ItemA and ItemB extending an abstract class AbstractItem)

During marshaling a namespace is specified with QName (can't do without as it's part of the framework I'm obliged to use ...)

    Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
    JAXBContext context = JAXBContext.newInstance(retour.getClass());
    Marshaller marshaller = context.createMarshaller();
    QName qtag = new QName(retour.getNameSpace(), retour.getName());
    marshaller.marshal(new JAXBElement(qtag, retour.getClass(), retour), document);

    return document.getDocumentElement();

The generated XML looks something like :

<ns2:retour xmlns:ns2="https://my.custom.namespace">
  <items>
         <item xsi:type="itemA" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <blabla>test</blabla>
            <blabla1>A</blabla1>
         </item>
         <item xsi:type="itemB" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <blabla>test</blabla>
            <blabla2>01.01.2022</blabla2>
         </item>
     </items>
 </ns2:retour>

This xml is invalid with respect to the xsd because the types itemA and itemB are unknown. What is expected here is instead xsi:type="ns2:itemA" resp. xsi:type="ns2:itemB"

Is there an annotation that allows to force jaxb to annotate the xsi:type with the QName namespace given when marshaling?


Solution

  • I managed to enforce the namespace prefix by adding it in a package info:

    @javax.xml.bind.annotation.XmlSchema(namespace ="https://my.custom.namespace")
    package the.package.containing.my.jaxb.classes;
    

    After that addition, the generated xml contains xsi:type="ns2:itemB" instead of xsi:type="itemB" as expected.

    It's not really proper that the namespace is defined in two different palces (both the package info) and the QName (which is enforced by the framework I'm using). But well, it does the trick ...