Search code examples
javaxmlxsdjaxbxjc

JAXB compiler is binding xs:boolean to Java Boolean wrapper class, instead of boolean primitive type


I'm migrating a project from JAXB 1.0 to JAXB 2.1 and I'm having problems with the datatype mapping.

I'm using the Ant xjc binding compiler, and I've successfully configured the global bindings such that (for example) xs:date maps to java.util.Calendar.

However I'm getting generated methods which return Boolean, whereas I want boolean.

Here is the complex type:

<xs:element name="usage-auth-rate-charge">
    <xs:complexType>
        <xs:sequence>
            <xs:element name="service-id" type="xs:string"/>
            <xs:element name="pricepoint_custom_fields_required" type="xs:boolean" minOccurs="0"/>
        </xs:sequence>
    </xs:complexType>
</xs:element>

And the generated class looks like this:

public class UsageAuthRateCharge {
........
public Boolean isPricepointCustomFieldsRequired() {
    return pricepointCustomFieldsRequired;
}

The problem is that although boxing will work, if the supplied XML doesn't contain a value for pricepoint_custom_fields_required, the class's Boolean field is null, instead of false. So I get NullPointerExceptions when doing something like this:

methodWhichTakesPrimitiveBooleanArg(myUsageAuthRateChargeInstance.isPricepointCustomFieldsRequired());

because it tries to unbox the Boolean passed in - except it's null.


I can't change the schema, and I can't adjust all the client code to do the null checks.

I've set the optionalProperty attribute in my binding.xml as follows:

<globalBindings optionalProperty="primitive">

In the spec, it says: "If the attribute’s value is "primitive", it binds as it did in JAXB 1.0"

Yet this is clearly not happening.

How can I solve this problem?

UPDATE:

This is now fixed in jaxb 2.2.9: https://java.net/jira/browse/JAXB/fixforversion/16850


Solution

  • I got bored of waiting for a fix from the dev team so I rolled up my sleeves and did it myself.

    I'm including the code below to help people for whom this is also an issue.

    Disclaimer: my code probably isn't the best way to solve the problem but it works for me.

    The generated code now looks like this:

    public boolean isPricepointCustomFieldsRequired() {
        if (pricepointCustomFieldsRequired == null) {
            return false;
        } else {
            return pricepointCustomFieldsRequired;
        }
    }
    

    And the modification is as follows:

    com.sun.tools.xjc.reader.xmlschema.bindinfo.BIProperty:createElementProperty, line ~358

    After the line

    types.addTo(prop);

    insert the following code:

    if (prop.isOptionalPrimitive() && getOptionalPropertyMode() == OptionalPropertyMode.PRIMITIVE &&
        !prop.getTypes().isEmpty() && "boolean".equals(prop.getTypes().get(0).getTypeName().getLocalPart()) )   {
            prop.defaultValue= CDefaultValue.create(CBuiltinLeafInfo.BOOLEAN, new XmlString("false"));
        }