I am trying to write the class in order to write an element with attributes in JAXB. In this XML there are some default values whether they be Strings, ints, or custom class types.
The following cut down example:
@XmlAccessorType(XmlAccessType.NONE)
@XmlRootElement(name = "FIELD")
public class TestLayoutNode
{
// I want to not write this to the xml when it is 0
@XmlAttribute(name = "num")
private int number;
// I want to not write this when it is "default"
@XmlAttribute(name = "str")
private String str;
}
As per JAXB Avoid saving default values I know if I want to not write the String I can modify the getters/setters to write null and read in the default value if it reads in null.
However, with the int I am not sure what to do as it will always have the value 0 unless it is specifically changed.
Is there a nicer way to do this? I could change the internal data types to String and then cast it whenever it is needed but that's a bit messy.
You could do the following by changing the fields to be the object types by default null values do not appear in the XML representation) and putting some logic in the getters:
@XmlAccessorType(XmlAccessType.NONE)
@XmlRootElement(name = "FIELD")
public class TestLayoutNode
{
@XmlAttribute(name = "num")
private Integer number;
@XmlAttribute
private String str;
public int getNumber() {
if(null == number) {
return 0;
} else {
return number;
}
}
public void setNumber(int number) {
this.number = number;
}
public String getStr() {
if(null == str) {
return "default";
} else {
return str;
}
}
public void setStr(String str) {
this.str = str;
}
}
If you want to allow the set operation to return a property to its default state then you need to add logic in the set method.
public void setNumber(int number) {
if(0 == number) {
this.number = null;
} else {
this.number = number;
}
}
Alternatively you could offer an unset method:
public void unsetNumber() {
this.number = null;
}
null
If you want to allow the str
property to be set to null
so that the get method will return null
and not "default"
then you can maintain a flag to track if it has been set:
private strSet = false;
public String getStr() {
if(null == str && !strSet) {
return "default";
} else {
return str;
}
}
public void setStr(String str) {
this.str = str;
this.strSet = true;
}
Blaise, don't you think that the solution is pretty verbose?
Yes
I mean that such use case should be probably supported by framework. For example using annotation like @DefaultValue.
How JAXB Supports Default Values Today
If a node is absent from the XML then a set is not performed on the corresponding field/property in the Java Object. This means whatever value you have initialized the property to be is still there. On a marshal since the value is populated it will be marshalled out.
What is Really Being Asked For
What is really being asked for is to not marshal the field/property when it has the default value. In this way you want the marshal behaviour to be the same for null and default values. This introduces some problems to be solved:
What Are People Doing Today?
Generally for this use case people would just change the int
property to Integer
and have null
be the default. I haven't encountered someone asking for this behaviour for a String
before.
Use Integer
instead of primitive int
. Replace all primitive types with their object counterparts, then you can use NULL
.
As per the string default value, use and modify the getter
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "FIELD")
public class NullAttrs {
private Integer number;
private String str;
public void setNumber(Integer number) {
this.number = number;
}
@XmlAttribute(name = "num")
public Integer getNumber() {
return number;
}
public void setStr(String str) {
this.str = str;
}
@XmlAttribute(name = "str")
public String getStr() {
if (str != null && str.equalsIgnoreCase("default"))
return null;
else if (str == null)
return "default";
else
return str;
}
public static void main(String[] args) throws JAXBException {
JAXBContext jc = JAXBContext.newInstance(NullAttrs.class);
NullAttrs root = new NullAttrs();
root.setNumber(null);
root.setStr("default");
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(root, System.out);
}
}
Result in this case would be, empty FIELD
:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<FIELD/>
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