chama
chama

Reputation: 6163

Is there a way to specify that JAXB should only print an attribute if it doesn't have a specific value?

I am working with JAXB to marshal and unmarshal a java class.

This is the xml I'm looking for:

<tag name="example" attribute1="enumValue"/>

if attribute1 is set to the default value, I don't want that attribute to print at all, so it would look like this:

<tag name="example"/>

Is there a way to do this?

Right now I have a getter/setter pair that looks like this:

@XmlAttribute(name="attribute1")
public EnumExample getEnumExample() {
    return this.enumExample;
}

public void setEnumExample(final EnumExample enumExample) {
    this.enumExample = enumExample;
}

Upvotes: 4

Views: 2510

Answers (3)

bdoughan
bdoughan

Reputation: 149047

You could use an XmlAdapter for this use case:

XmlAdapter (Attribute1Adapter)

You could leverage the fact that JAXB will not marshal null attribute values and use an XmlAdapter to adjust the value being marshalled to XML.

import javax.xml.bind.annotation.adapters.XmlAdapter;
import forum16972549.Tag.Foo;

public class Attribute1Adapter extends XmlAdapter<Tag.Foo, Tag.Foo>{

    @Override
    public Foo unmarshal(Foo v) throws Exception {
        return v;
    }

    @Override
    public Foo marshal(Foo v) throws Exception {
        if(v == Foo.A) {
            return null;
        }
        return v;
    }

}

Domain Model (Tag)

The @XmlJavaTypeAdapter annotation is used to associate the XmlAdapter.

import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Tag {

    enum Foo {A, B};

    @XmlAttribute
    @XmlJavaTypeAdapter(Attribute1Adapter.class)
    private Foo attribute1;

    public Foo getAttribute1() {
        return attribute1;
    }

    public void setAttribute1(Foo attribute1) {
        this.attribute1 = attribute1;
    }

}

Demo

Below is some demo code you can use to prove that everything works.

import javax.xml.bind.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Tag.class);
        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

        Tag tag = new Tag();
        tag.setAttribute1(Tag.Foo.A);
        System.out.println(tag.getAttribute1());
        marshaller.marshal(tag, System.out);

        tag.setAttribute1(Tag.Foo.B);
        System.out.println(tag.getAttribute1());
        marshaller.marshal(tag, System.out);
    }

}

Output

Below is the output from running the demo code.

A
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<tag/>
B
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<tag attribute1="B"/>

Upvotes: 5

bdoughan
bdoughan

Reputation: 149047

Tag

You could leverage the fact that JAXB will not marshal null attribute values and add some logic to your properties and then use JAXB to map to the field.

import javax.xml.bind.annotation.*;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Tag {

    private static Foo ATTRIBUTE1_DEFAULT = Foo.A;

    enum Foo {A, B};

    @XmlAttribute
    private Foo attribute1;

    public Foo getAttribute1() {
        if(null == attribute1) {
            return ATTRIBUTE1_DEFAULT;
        }
        return attribute1;
    }

    public void setAttribute1(Foo attribute1) {
        if(ATTRIBUTE1_DEFAULT == attribute1) {
            this.attribute1 = null;
        } else {
            this.attribute1 = attribute1;
        }
    }

}

Demo

import javax.xml.bind.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Tag.class);
        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

        Tag tag = new Tag();
        tag.setAttribute1(Tag.Foo.A);
        System.out.println(tag.getAttribute1());
        marshaller.marshal(tag, System.out);

        tag.setAttribute1(Tag.Foo.B);
        System.out.println(tag.getAttribute1());
        marshaller.marshal(tag, System.out);
    }

}

Output

A
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<tag/>
B
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<tag attribute1="B"/>

Upvotes: 2

veebee
veebee

Reputation: 61

AFAIK, this is not possible directly using JAXB annotations. But using required=true like this,

@XmlAttribute(required=true name="attribute1") 
private String enumExample;

we can do a workaround. Before calling the setter on that attribute, we can check if the value that will be set is the default value. If yes, we can pass null to that setter and that attribute will not be visible after marshalling.

Upvotes: 1

Related Questions