I have a String property in an object annotated as follows:
@XmlElement(name = "Item", required = true, nillable = true)
private String item;
The result after marshaling is
<Item xsi:nil="true"/>
while I would like it to be
<Item/>
since the third-party service accepting my XML messages wants it like the latter case. I am using jaxb2. Does anyone knows how I could possibly do this?
Thanks a lot
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
The following example requires the use of MOXy as the JAXB provider. This is because the JAXB RI does not call the XmlAdapter
when the field/property is null. For information on specifying MOXy as your JAXB provider see:
StringAdapter
The XmlAdapter
will convert the String value to an object with a property annotated with @XmlValue
.
package forum8986842;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class StringAdapter extends XmlAdapter<StringAdapter.AdaptedString, String>{
@Override
public String unmarshal(AdaptedString adaptedString) throws Exception {
if(null == adaptedString) {
return null;
}
String string = adaptedString.value;
if("".equals(string)) {
return null;
}
return string;
}
@Override
public AdaptedString marshal(String string) throws Exception {
AdaptedString adaptedString = new AdaptedString();
adaptedString.value = string;
return adaptedString;
}
public static class AdaptedString {
@XmlValue public String value;
}
}
Root
The @XmlJavaTypeAdapter
annotation is used to specify the XmlAdapter
:
package forum8986842;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@XmlRootElement(name="Root")
public class Root {
private String item;
@XmlElement(name = "Item", required = true, nillable = true)
@XmlJavaTypeAdapter(StringAdapter.class)
public String getItem() {
return item;
}
public void setItem(String item) {
this.item = item;
}
}
Demo
The following code can be used to demonstrate the above mapping. Two documents are used one with an empty Item
element, and the other with a populated Item
element.
package forum8986842;
import java.io.StringReader;
import javax.xml.bind.*;
public class Demo {
private JAXBContext jc;
public Demo() throws JAXBException {
jc = JAXBContext.newInstance(Root.class);
}
public static void main(String[] args) throws Exception {
Demo demo = new Demo();
demo.demo("<Root><Item/></Root>");
demo.demo("<Root><Item>Hello World</Item></Root>");
}
private void demo(String xml) throws JAXBException {
System.out.println("\n\nINPUT: " + xml);
StringReader stringReader = new StringReader(xml);
Unmarshaller unmarshaller = jc.createUnmarshaller();
Root root = (Root) unmarshaller.unmarshal(stringReader);
System.out.println("ITEM: " + root.getItem());
System.out.print("OUTPUT: ");
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
marshaller.marshal(root, System.out);
}
}
Output
The following is the output from running the demo code:
INPUT: <Root><Item/></Root>
ITEM: null
OUTPUT: <Root><Item/></Root>
INPUT: <Root><Item>Hello World</Item></Root>
ITEM: Hello World
OUTPUT: <Root><Item>Hello World</Item></Root>
For More Information
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