2

We use Jaxb (jaxb-api 2.2.5) to generate a Java class from an XSD. The 'someField' element has a nillable='true' attribute and an (implicit) minoccurs='1'. There is also an optional 'order' attribute.

When we set the order attribute on someField, but no value, JAXB will generate the XML element in the request without nill='true' and this is not accepted by the XSD and results in a SOAP fault.

The XSD for the field:

<xs:element name="someField" nillable="true">
    <xs:complexType>
        <xs:simpleContent>
            <xs:extension base="iata:AlphaNumericStringLength1to19">
                <xs:attribute name="order" type="xs:integer" use="optional"/>
            </xs:extension>
        </xs:simpleContent>
    </xs:complexType>
</xs:element>

Jaxb translates this to the following field on our Java class:

@XmlElement(required = true, nillable = true)
protected SomeParentType.SomeField someField;

The SomeField class looks like this:

public static class SomeField{

    @XmlValue
    protected String value;
    @XmlAttribute
    protected BigInteger order;

    // getters  + setters
}

When we set the order ATTRIBUTE to 2 (for example), and set nothing for the value, JAXB will generate this:

<pay1:someField order="2"/> 

This is not valid according to the XSD and it results in a SOAP fault when we send it.

This does work:

<pay1:someField xsi:nil="true" order="2"/>

Do you know how we can get JAXB be to generate the latter? And is JAXB actually wrong in generating the nil-less version?

1 Answer 1

3

And is JAXB actually wrong in generating the nil-less version?

Let me get back to you on this.


Do you know how we can get JAXB be to generate the latter?

Below is what you can do

Java Model

SomeParentType

To get the behaviour you are looking for with existing JAXB libraries the domain model needs to be of the following form:

import java.math.BigInteger;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.*;

@XmlRootElement
public class SomeParentType {

    @XmlElementRef(name="someField")
    protected JAXBElement<SomeParentType.SomeField> someField;

    public static class SomeField{

        @XmlValue
        protected String value;
        @XmlAttribute
        protected BigInteger order;

        // getters  + setters
    }

}

Registry

To go along with the @XmlElementRef we need to have an @XmlElementDecl on a class annotated with @XmlRegistry.

import javax.xml.namespace.QName;
import javax.xml.bind.*;
import javax.xml.bind.annotation.*;

@XmlRegistry
public class Registry {

    @XmlElementDecl(name="someField")
    public JAXBElement<SomeParentType.SomeField> createSomeField(SomeParentType.SomeField someField) {
        return new JAXBElement(new QName("someField"), SomeParentType.SomeField.class, someField);
    }

}

Demo Code

Below is some demo code to exercise your use case:

import javax.xml.bind.*;
import java.math.BigInteger;

public class Demo {

    public static void main(String[] args) throws Exception {
        // Create the JAXBContext to bring in the Registry
        JAXBContext jc = JAXBContext.newInstance(SomeParentType.class, Registry.class);

        // Create the instance of SomeField
        SomeParentType.SomeField sf = new SomeParentType.SomeField();
        sf.order = new BigInteger("1");

        // Wrap the SomeField in a JAXBElement & specify the nil aspect
        Registry registry = new Registry();
        JAXBElement<SomeParentType.SomeField> jaxbElement = registry.createSomeField(sf);
        jaxbElement.setNil(true);

        SomeParentType spt = new SomeParentType();
        spt.someField = jaxbElement;

        // Marshal the domain model to XML
        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(spt, System.out);
    }

}

Output

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<someParentType>
    <someField xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" order="1" xsi:nil="true"/>
</someParentType>
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for your elaborate explanation. We will try this and see if it works for us.
Hey Blaise, one more question. We are wondering if the solution you suggest is the only solution for this problem. Would it somehow be possible to get JAXB to create the nill=true attribute without using custom code? And I am also very interested in what you think about JAXB 'forgetting' the nill=true attribute. Your posts suggests this has been a conscious implementation choice in JAXB. I'm curious why, because my feeling says nill pertains to the value and when the value is not there this would mean nill=true should be in the XML, even though there is an order attribute. Thanks in advance. J

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.