xmljaxb

JAXB Unmarshalling nils


@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "healthCheck",
        propOrder = { "healthy", "id" })
public class HealthCheck {

    @XmlElement(nillable = true)
    protected Boolean healthy;
    @XmlElement(nillable = true)
    protected String id;
}

HealthCheck healthCheck = new HealthCheck(); healthCheck.setHealthy(true); healthCheck.setId("123");

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:healthCheck xmlns:ns2="">
    <healthy xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
    <id>123</id>
</ns2:healthCheck>

When unmarshalling it on server, I need the information that is set to nil. How can I do this? In general I need the information about nil fields. I dont know what is the better approach to unmarshal. I have to set these fields to null.


Solution

  • JAXB provides two settings that may help you: generateElementProperty and generateIsSetMethod.

    From the JAXB Spec, the generateElementProperty="true" will generate properties that return JAXBElement, unless overriden by <jaxb:property generateElementProperty="false"/> on individual properties.

    And when generateIsSetMethod="true" then additional methods such as isSetFoo() are generated.

    By setting generateElementProperty="true", each "getter" returns a JAXBElement type that 1) wraps the actual value in a JAXBElement method named value() and 2) provides a JAXBElement method named isNil() that returns true when the XML instance declares an "xsi:nil" attribute on the element. The downside is that you need to use getFoo().value() to reference the actual value.

    Alternatively, you can set generateIsSetMethod="true" to tell the XJC engine to generate methods like isSetFoo() that return true when the field is not set during unmarshaling. One thing to be aware of is that the XJC engine may produce a "getter" that returns a default value when the field is not set. The 'isSetFoo() method tests the field and not "getter".

    Note: One other approach, shown in Nothing, uses a DocumentBuilderFactory from javax.xml.parsers to parse the XML into a Document instance that can be passed into jaxbContext.createBinder().unmarshal(doc, Nothings.class) to unmarshal the XML. The difference, is the use of a JAXB Binder instance to do the unmarshalling. This provides a method to get the XML element associated with any of your generated objects. You can loop over the element's children to get the actual xsi:nil attribute associated with each property using childElement.getAttributeNS(W3C_XML_SCHEMA_INSTANCE_NS_URI, "nil")

    Here's the schema and XML I used for my experimenting, see also HiSrc HigherJAXB Text Nothing that uses these settings:

    nothing.xjb

    <?xml version="1.0" encoding="UTF-8"?>
    <jaxb:bindings jaxb:version="3.0"
        xmlns:jaxb="https://jakarta.ee/xml/ns/jaxb"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    >
        <!--  Global Bindings -->
        <jaxb:globalBindings generateElementProperty="true" generateIsSetMethod="true" >
            <jaxb:serializable uid="20250501" />
        </jaxb:globalBindings>
    </jaxb:bindings>
    

    And here is the XML schema that tghe binding file references:

    nothing.xsd

    <?xml version="1.0" encoding="UTF-8"?>
    <xs:schema elementFormDefault="unqualified"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        xmlns:jaxb="https://jakarta.ee/xml/ns/jaxb"
        jaxb:version="3.0"
        xmlns:tns="urn:example.org:nothing"
        targetNamespace="urn:example.org:nothing"
    >
        <xs:element name="Nothing">
            <xs:complexType>
                <xs:sequence>
                    <xs:element name="optionalNillableString" type="xs:string" minOccurs="0" nillable="true"/>
                    <xs:element name="requiredNillableString" type="xs:string" minOccurs="1" nillable="true"/>
                    <xs:element name="optionalNillableStrings" type="xs:string" minOccurs="0" maxOccurs="unbounded" nillable="true"/>
                    <xs:element name="requiredNillableStrings" type="xs:string" minOccurs="1" maxOccurs="unbounded" nillable="true"/>
                </xs:sequence>
                <xs:attribute name="id" type="xs:int" />
            </xs:complexType>
        </xs:element>
        
        <xs:element name="Nothings">
            <xs:complexType>
                <xs:sequence>
                    <xs:element ref="tns:Nothing" maxOccurs="unbounded"/>
                </xs:sequence>
            </xs:complexType>
        </xs:element>
            
    </xs:schema>
    

    And here is an XML sample file that can be unmarshaled and marshaled to see the effects of changing the global settings:

    <?xml version="1.0" encoding="UTF-8"?>
    <no:Nothings
        xmlns:no="urn:example.org:nothing"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="urn:example.org:nothing ../../main/resources/nothing.xsd"
    >
        <no:Nothing id="101">
            <optionalNillableString xsi:nil="true"/>
            <requiredNillableString xsi:nil="true"/>
            <optionalNillableStrings xsi:nil="true"/>
            <optionalNillableStrings xsi:nil="true"/>
            <requiredNillableStrings xsi:nil="true"/>
            <requiredNillableStrings xsi:nil="true"/>
        </no:Nothing>
        <no:Nothing id="102">
            <optionalNillableString xsi:nil="false"/>
            <requiredNillableString xsi:nil="false"/>
            <optionalNillableStrings xsi:nil="false"/>
            <optionalNillableStrings xsi:nil="false"/>
            <requiredNillableStrings xsi:nil="false"/>
            <requiredNillableStrings xsi:nil="false"/>
        </no:Nothing>
        <no:Nothing id="103">
            <optionalNillableString/>
            <requiredNillableString/>
            <optionalNillableStrings/>
            <optionalNillableStrings/>
            <requiredNillableStrings/>
            <requiredNillableStrings/>
        </no:Nothing>
        <no:Nothing id="104">
            <requiredNillableString/>
            <requiredNillableStrings/>
        </no:Nothing>
        <no:Nothing id="105">
            <optionalNillableString>ONS01</optionalNillableString>
            <requiredNillableString>RNS01</requiredNillableString>
            <optionalNillableStrings>ONSS01</optionalNillableStrings>
            <optionalNillableStrings>ONSS02</optionalNillableStrings>
            <optionalNillableStrings xsi:nil="true"/>
            <optionalNillableStrings xsi:nil="false"/>
            <requiredNillableStrings>RNSS01</requiredNillableStrings>
            <requiredNillableStrings>RNSS02</requiredNillableStrings>
            <requiredNillableStrings xsi:nil="true"/>
            <requiredNillableStrings xsi:nil="false"/>
        </no:Nothing>
    </no:Nothings>