views:

135

answers:

1

I am using JAXB (EclipseLink implementation) in a JAX-RS webservice. When an empty element is passed in the XML request an empty object is created. Is it possible to set JAXB to create a null object instead?

Example XML:

<RootEntity>
    <AttributeOne>someText</AttributeOne>
    <EntityOne id="objectID" />
    <EntityTwo />
</RootEntity>

When unmarshalling, an instance of EntityOne is created and the id attribute set to "objectID" and an instance of EntityTwo is created with null attributes. Instead I would like a null object for EntityTwo as having an empty object is causing me problems with JPA persistence operations.

A: 

You can specify this behaviour using MOXy's NullPolicy. You will need to create a DescriptorCustomizer to modify the underlying mappings. Don't worry it's easier than it sounds, I'll demonstrate below:

import org.eclipse.persistence.config.DescriptorCustomizer;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.oxm.mappings.XMLCompositeObjectMapping;
import org.eclipse.persistence.oxm.mappings.nullpolicy.XMLNullRepresentationType;

public class RootEntityCustomizer implements DescriptorCustomizer {

    @Override
    public void customize(ClassDescriptor descriptor) throws Exception {
        XMLCompositeObjectMapping entityTwoMapping = (XMLCompositeObjectMapping) descriptor.getMappingForAttributeName("entityTwo");

        entityTwoMapping.getNullPolicy().setNullRepresentedByEmptyNode(true);
        entityTwoMapping.getNullPolicy().setMarshalNullRepresentation(XMLNullRepresentationType.EMPTY_NODE);
    }

}

Below is how you associate the customizer with your model class:

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

import org.eclipse.persistence.oxm.annotations.XmlCustomizer;

@XmlRootElement(name="RootEntity")
@XmlCustomizer(RootEntityCustomizer.class)
public class RootEntity {

    private String attributeOne;
    private Entity entityOne;
    private Entity entityTwo;

    @XmlElement(name="AttributeOne")
    public String getAttributeOne() {
        return attributeOne;
    }

    public void setAttributeOne(String attributeOne) {
        this.attributeOne = attributeOne;
    }

    @XmlElement(name="EntityOne")
    public Entity getEntityOne() {
        return entityOne;
    }

    public void setEntityOne(Entity entityOne) {
        this.entityOne = entityOne;
    }

    @XmlElement(name="EntityTwo")
    public Entity getEntityTwo() {
        return entityTwo;
    }

    public void setEntityTwo(Entity entityTwo) {
        this.entityTwo = entityTwo;
    }

}

In the next version of MOXy (2.2) you will be able to do this via annotations.

@XmlElement(name="EntityTwo")
@XmlNullPolicy(emptyNodeRepresentsNull=true,
              nullRepresentationForXml=XmlMarshalNullRepresentation.EMPTY_NODE)
public Entity getEntityTwo() {
    return entityTwo;
}

You can try this now with one of the EclipseLink 2.2.0 nightly builds:

Blaise Doughan
I am using EclipseLink 2.2.0, so added the annotations to my class. Unfortunately it has the behaviour of setting an element to null when it is empty but has a property defined. For example EntityOne in the above example is now returning a null object. Is this the expected behaviour?
sdoca
This is a bug, see https://bugs.eclipse.org/322183 . We will get a fix in this week. To see the correct behaviour you could make the id property on Entity an element instead of an attribute.
Blaise Doughan
I had changed from attributes to properties and it means a little more verbose XML, but it works. Thanks!
sdoca
As promised the attribute fix is available in EclipseLink 2.2.0 starting with the Aug 12 nightly drop available at http://www.eclipse.org/eclipselink/downloads/nightly.php
Blaise Doughan