April 5, 2012

JAXB and Unmapped Properties

JAXB (JSR-222) is configuration by exception, meaning that there is a default mapping applied to domain objects.  This means that sometimes you need to explicitly exclude a field/property.  In this post I'll discuss how this can be done using @XmlTransient or @XmlAccessorType(XmlAccessType.NONE) and when each option is appropriate.

@XmlTransient

When you mark a field/property with @XmlTransient you are explicitly telling your JAXB implementation to treat it as an unmapped property.  This is useful when less than half of the fields/properties are unmapped.

package blog.unmapped;

import java.util.List;
import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
public class Customer {

    @XmlTransient
    private int id;

    private String firstName;

    private String lastName;

    private Address billingAddress;

    private Address shippingAddress;

    private List<PhoneNumber> phoneNumbers;

}

Below is what the metadata would look like using MOXy's external mapping document: 
<?xml version="1.0" encoding="UTF-8"?>
<xml-bindings
    xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
    package-name="blog.unmapped">
    <java-types>
        <java-type name="Customer" xml-accessor-type="FIELD">
            <java-attributes>
                <xml-transient java-attribute="id"/>
            </java-attributes>
        </java-type>
    </java-types>
</xml-bindings>

If more than half of the fields/properties are unmapped then we stop gaining the benefit of configuration by exception since we need to do more work to exclude properties with @XmlTransient than we would have had to do to map the mapped properties.  Next I'll demonstrate how we can leverage @XmlAccessorType(XmlAccessType.NONE) for this use case.

package blog.unmapped;

import java.util.List;
import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
public class Customer {

    @XmlTransient
    private int id;

    private String firstName;

    private String lastName;

    @XmlTransient
    private Address billingAddress;

    @XmlTransient
    private Address shippingAddress;

    @XmlTransient
    private List<PhoneNumber> phoneNumbers;

}


@XmlAccessorType(XmlAccessType.NONE)

By setting @XmlAccessorType(XmlAccessType.NONE) we are disabling configuration by exception.  Now only explicitly mapped properties will be mapped.  This is useful when less than half of the fields/properties of a domain object are mapped.

package blog.unmapped;

import java.util.List;
import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.NONE)
public class Customer {

    private int id;

    @XmlElement
    private String firstName;

    @XmlElement
    private String lastName;

    private Address billingAddress;

    private Address shippingAddress;

    private List<PhoneNumber> phoneNumbers;

}

Below is what the metadata would look like using MOXy's external mapping document: 
<?xml version="1.0" encoding="UTF-8"?>
<xml-bindings
    xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
    package-name="blog.unmapped">
    <java-types>
        <java-type name="Customer" xml-accessor-type="NONE">
            <java-attributes>
                <xml-element java-attribute="firstName"/>
                <xml-element java-attribute="lastName"/>
            </java-attributes>
        </java-type>
    </java-types>
</xml-bindings>

Further Reading

 If you enjoyed this post then you also like:

3 comments:

  1. What is the equivalent for the MOXy mapped metadata "binding/oxm.xml" file?

    ReplyDelete
    Replies
    1. I have updated the post to show what the oxm.xml files would look like.

      -Blaise

      Delete