JAXB - Suppress Boolean attribute if false
Let's say that I have a class
@XmlRootElement(name="thing")
public class Thing{
private String name;
private boolean awesome;
@XmlValue public void setName(String name) {
this.name = name;
}
public String getName() {
return this.value;
}
@XmlAttribute public void setAwesome(boolean awesome) {
this.awesome = awesome;
}
public boolean isAwesome() {
return this.awesome;
}
}
If I create some things, then marshall them to XML, it looks like this:
A flying ninja:
<thing awesome="true">flying ninja</thing>
A regular old popcorn ball:开发者_运维百科
<thing awesome="false">popcorn ball</thing>
But... what I would like to do is change the way that my boolean attributes are marshalled. I would rather see the popcorn ball look like this, supressing the awesome attribute:
<thing>popcorn ball</thing>
How can I do this?
Thanks so much!
Note: I'm the EclipseLink JAXB (MOXy) lead, and a member of the JAXB 2.X (JSR-222) expert group.
Using MOXy you can do the XmlAdapter
approach as suggested by Hovercraft Full Of Eels. It would look something like:
BooleanAdapter
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class BooleanAdapter extends XmlAdapter<Boolean, Boolean> {
@Override
public Boolean unmarshal(Boolean v) throws Exception {
return Boolean.TRUE.equals(v);
}
@Override
public Boolean marshal(Boolean v) throws Exception {
if(v) {
return v;
}
return null;
}
}
Thing
You associate your property with the XmlAdapter
using the @XmlJavaTypeAdapter
annotation as follows:
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlValue;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@XmlRootElement(name="thing")
public class Thing{
private String name;
private boolean awesome;
@XmlValue public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
@XmlAttribute
@XmlJavaTypeAdapter(BooleanAdapter.class)
public void setAwesome(boolean awesome) {
this.awesome = awesome;
}
public boolean isAwesome() {
return this.awesome;
}
}
Demo
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Thing.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
Thing thing = new Thing();
thing.setName("popcorn ball");
thing.setAwesome(false);
marshaller.marshal(thing, System.out);
thing.setAwesome(true);
marshaller.marshal(thing, System.out);
}
}
Output
<?xml version="1.0" encoding="UTF-8"?>
<thing>popcorn ball</thing>
<?xml version="1.0" encoding="UTF-8"?>
<thing awesome="true">popcorn ball</thing>
Using the JAXB RI
If you run this example with the JAXB RI you will get the following exception:
Exception in thread "main" com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
Adapter example.BooleanAdapter is not applicable to the field type boolean.
this problem is related to the following location:
at @javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter(type=class javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter$DEFAULT, value=class example.BooleanAdapter)
at public boolean example.Thing.isAwesome()
at forum251.Thing
For More Information
- http://bdoughan.blogspot.com/2011/05/specifying-eclipselink-moxy-as-your.html
- http://bdoughan.blogspot.com/2010/07/xmladapter-jaxbs-secret-weapon.html
- http://bdoughan.blogspot.com/2011/05/jaxb-and-joda-time-dates-and-times.html
Achieve this by using a nullable type, and registering a JAXB listener to your class. Within the JAXB listener, set your attribute to null
if you dont want to marshal it. This approach should work in any JAXB implementation.
Your (Boolean or other) attribute
@XmlAttribute(required = false)
private Boolean valueUnknown;
The JAXB beforeMarshal handler
@SuppressWarnings("PMD")
private void beforeMarshal(final Marshaller marshaller) {
// Remove the "valueUnknown" attribute if it is not true.
// Assigning a null value implies that the attribute is removed.
if(!valueUnknown) {
valueUnknown = null;
}
}
This approach can - for instance - yield the result below. Note that the attribute valueUnknown is only present when no value attribute is given.
<items>
<item xsi:type="eduDataExchange:compoundValue" valueUnknown="true"/>
<item xsi:type="eduDataExchange:compoundValue" value="4" percentage="3"/>
</items>
I'm not familiar with JAXB (yet), but generally this sort of thing should be quite doable with XSLT processing or transforming.
Also, this question's answer mentions use of an XmlAdapter which looks to be directly applicable to your problem: How to let JAXB render boolean as 0 and 1, not true and false
replacing boolean with Boolean Object , it solved this issue for me .
Use :-
private Boolean awesome;
instead of :-
private boolean awesome;
精彩评论