开发者

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;
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜