I need to display null value as empty element in jaxb. I am using moxy implementation of jaxb. I found this option
@XmlNullPolicy(emptyNodeRepresentsNull = true, nullRepresentationForXml = XmlMarshalNullRepresentation.EMPTY_NODE)
Is there any similar extension that can be applied at Class level (for all elements defined in it)
Ways to represent a null value In an XML document, the usual way to represent a null value is to leave the element or attribute empty. Some business messages use a special value to represent a null value: <price>-999</price> .
When a top level class or an enum type is annotated with the @XmlRootElement annotation, then its value is represented as XML element in an XML document. This annotation can be used with the following annotations: XmlType , XmlEnum , XmlAccessorType , XmlAccessorOrder .
You can ignore null fields at the class level by using @JsonInclude(Include. NON_NULL) to only include non-null fields, thus excluding any attribute whose value is null. You can also use the same annotation at the field level to instruct Jackson to ignore that field while converting Java object to json if it's null.
A JavaBean property, when annotated with @XmlElement annotation is mapped to a local element in the XML Schema complex type to which the containing class is mapped.
I would strongly recommend representing null
with either the absence of the node or with the xsi:nil="true"
attribute. This works best with schema validation (i.e. <age/>
or <age></age>
is not a valid element of type xsd:int
. However if you can't here is how you can accomplish your use case:
STANDARD JAXB BEHAVIOUR
Using the standard APIs you can control whether null is represented as an absent node or with xsi:nil="true"
with the @XmlElement
annotation (see: http://blog.bdoughan.com/2012/04/binding-to-json-xml-handling-null.html).
import javax.xml.bind.annotation.*;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Address {
private String street;
@XmlElement(nillable=true)
private String city;
}
Below is the XML output if the values of both fields are null.
<?xml version="1.0" encoding="UTF-8"?>
<address>
<city xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
</address>
MOXy - OVERRIDING THIS BEHAVIOUR PER CLASS
MOXy does not provide an annotation to specify the null policy for all the properties on a class. However you can leverage a DescriptorCustomizer
via the @XmlCustomizer
annotation and tweak the native MOXy mapping metadata to accomplish the same thing.
DescriptorCustomizer (AddressCustomizer)
import org.eclipse.persistence.config.DescriptorCustomizer;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.mappings.DatabaseMapping;
import org.eclipse.persistence.oxm.mappings.XMLDirectMapping;
import org.eclipse.persistence.oxm.mappings.nullpolicy.XMLNullRepresentationType;
public class AddressCustomizer implements DescriptorCustomizer {
@Override
public void customize(ClassDescriptor descriptor) throws Exception {
for(DatabaseMapping mapping : descriptor.getMappings()) {
if(mapping.isAbstractDirectMapping()) {
XMLDirectMapping xmlDirectMapping = (XMLDirectMapping) mapping;
xmlDirectMapping.getNullPolicy().setMarshalNullRepresentation(XMLNullRepresentationType.EMPTY_NODE);
xmlDirectMapping.getNullPolicy().setNullRepresentedByEmptyNode(true);
}
}
}
}
DomainModel (Address)
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlCustomizer;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlCustomizer(AddressCustomizer.class)
public class Address {
private String street;
@XmlElement(nillable=true)
private String city;
}
Output
<?xml version="1.0" encoding="UTF-8"?>
<address>
<street/>
<city/>
</address>
MOXy - OVERRIDING THIS BEHAVIOUR FOR ALL CLASSES
If instead you want to override null handling for all of the mapped classes I would recommend using a SessionEventListener
instead. If you prefer you could also use this approach to update the metadata for a single class.
SessionEventListener (NullPolicySessionEventListener)
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.mappings.DatabaseMapping;
import org.eclipse.persistence.oxm.mappings.XMLDirectMapping;
import org.eclipse.persistence.oxm.mappings.nullpolicy.XMLNullRepresentationType;
import org.eclipse.persistence.sessions.*;
public class NullPolicySessionEventListener extends SessionEventAdapter {
@Override
public void preLogin(SessionEvent event) {
Project project = event.getSession().getProject();
for(ClassDescriptor descriptor : project.getOrderedDescriptors()) {
for(DatabaseMapping mapping : descriptor.getMappings()) {
if(mapping.isAbstractDirectMapping()) {
XMLDirectMapping xmlDirectMapping = (XMLDirectMapping) mapping;
xmlDirectMapping.getNullPolicy().setMarshalNullRepresentation(XMLNullRepresentationType.EMPTY_NODE);
xmlDirectMapping.getNullPolicy().setNullRepresentedByEmptyNode(true);
}
}
}
}
}
Demo Code
import java.util.*;
import javax.xml.bind.*;
import org.eclipse.persistence.jaxb.JAXBContextProperties;
import org.eclipse.persistence.sessions.SessionEventListener;
public class Demo {
public static void main(String[] args) throws Exception {
Map<String, Object> properties = new HashMap<String, Object>(1);
SessionEventListener sessionEventListener = new NullPolicySessionEventListener();
properties.put(JAXBContextProperties.SESSION_EVENT_LISTENER, sessionEventListener);
JAXBContext jc = JAXBContext.newInstance(new Class[] {Address.class}, properties);
Address address = new Address();
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(address, System.out);
}
}
Output
<?xml version="1.0" encoding="UTF-8"?>
<address>
<street/>
<city/>
</address>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With