Search code examples
javaxmljaxbmarshalling

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!


Solution

  • 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