I'm trying to marshal an element which can be null and in some cases should be not written in the final XML at all, in some other cases I should specify that it is nillable.
Consider the following example
<root>
<element>
<sub1>Whatever1</sub1>
<sub2 xsi:nil="true"/>
</element>
<element>
<sub1>Whatever2</sub1>
<sub2>Not empty</sub2>
</element>
<element>
<sub1>Whatever3</sub1>
</element>
</root>
The element "sub2" is the one I'm having trouble with.
From my understanding I can easily achieve the first 2 cases with the Element class declared as follows:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "element", propOrder = {
"sub1",
"sub2",
})
public class Element {
@XmlElement(required = true)
public String sub1;
@XmlElement(nillable = true)
public String sub2;
//...
}
To obtain the last two instead, I would do:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "element", propOrder = {
"sub1",
"sub2",
})
public class Element {
@XmlElement(required = true)
public String sub1;
@XmlElement(required = false) //I could omit it entirely
public String sub2;
//...
}
Is there a way to obtain both?
I'm forced to Java 6 / JAXB 2.1.10.
Thank you.
Yes, it is possible to have elements which are both not required and nillable. There are a few things you need to do to make this work:
JAXBElement<String>
instead of String
.ObjectFactory
class with a factory method.@XmlElementDecl
on the factory method in the ObjectFactory
and @XmlElementRef
on the field in class Element
.Example:
Make the field a JAXBElement<String>
with an @XmlElementRef
annotation:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "element", propOrder = {"sub1", "sub2"})
@XmlRootElement
public class Element {
@XmlElement(required = true)
public String sub1;
@XmlElementRef(name = "sub2", required = false)
public JAXBElement<String> sub2;
// ...
}
Create an ObjectFactory
class with a factory method, with an @XmlElementDecl
annotation. Note that the namespace and name of the @XmlElementRef
and @XmlElementDecl
annotation are the same:
@XmlRegistry
public class ObjectFactory {
@XmlElementDecl(name = "sub2")
public JAXBElement<String> createSub2(String value) {
return new JAXBElement<>(new QName(null, "sub2"),
String.class, Element.class, value);
}
}
Marshalling example 1: Have a value for sub2
:
ObjectFactory objectFactory = new ObjectFactory();
Element element = new Element();
element.setSub1("one");
element.setSub2(objectFactory.createSub2("two"));
JAXBContext context = JAXBContext.newInstance(ObjectFactory.class, Element.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(element, System.out);
Output:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<element>
<sub1>one</sub1>
<sub2>two</sub2>
</element>
Marshalling example 2: No element at all in the XML:
Element element = new Element();
element.setSub1("one");
// Leave the field sub2 set to null
Output:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<element>
<sub1>one</sub1>
</element>
Marshalling example 3: Create an element with the value null
which will appear as an XML element which is set to nil
:
Element element = new Element();
element.setSub1("one");
element.setSub2(objectFactory.createSub2(null));
Output:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<element>
<sub1>one</sub1>
<sub2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
</element>
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