Paul Hanbury Paul Hanbury - 1 year ago 134
Java Question

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!

Answer Source

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

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download