I have a boolean field called a
and two methods void setA(String a)
and boolean isA()
. I have set @XmlAccessorType(XmlAccessType.NONE)
and used @XmlAttribute
for the setter.
Because the getter returns a boolean value but the setter expects a string JAX-B just ignores this setter. This is the cause for all kinds of bugs in the code because boolean values are not set correctly and debugging that is very annoying.
Is there a way to tell JAX-B to use the setter? Why is JAX-B confused by the getter method at all, I though using XmlAccessType.NONE
prevents all that implicit interpreting?
Plan B would be to let JAX-B fails if such a constellation appears, but how can this be done?
Thankful for any hint :-)
I would recommend using @XmlAccessType.FIELD
as suggested by Kevin combined with an XmlAdapter
to get the behaviour you are looking for:
Root
To get this example to work with the JAXB-RI I need to make the field of type Boolean
. If you are using EclipseLink JAXB (MOXy) then you can make the field boolean
.
package forum7876493;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@XmlRootElement
public class Root {
@XmlAttribute
@XmlJavaTypeAdapter(BooleanAdapter.class)
private Boolean a;
public boolean isA() {
return a;
}
public void setA(String s) {
this.a = "yes".equals(s) || "on".equals(s) || "in".equals(s);
}
}
BooleanAdapter
The XmlAdapter
is where you can add the logic that you have in your setA(String)
method.
package forum7876493;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class BooleanAdapter extends XmlAdapter<String, Boolean> {
@Override
public Boolean unmarshal(String s) throws Exception {
return "yes".equals(s) || "on".equals(s) || "in".equals(s);
}
@Override
public String marshal(Boolean b) throws Exception {
if(b) {
return "yes";
}
return "no";
}
}
Demo
package forum7876493;
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Root.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
Root root = (Root) unmarshaller.unmarshal(new File("src/forum7876493/input.xml"));
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(root, System.out);
}
}
input.xml
<?xml version="1.0" encoding="UTF-8"?>
<root a="on"/>
Output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root a="yes"/>
UPDATE
Alternatively you could introduce a String
getter for the a
property. You would need to make the isA()
method as @XmlTransient
:
package forum7876493;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
@XmlRootElement
public class Root {
private boolean a;
@XmlTransient
public boolean isA() {
return a;
}
@XmlAttribute
public String getA() {
if(a) {
return "yes";
}
return "no";
}
public void setA(String s) {
this.a = "yes".equals(s) || "on".equals(s) || "in".equals(s);
}
}