Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JAXB: XmlAdapter for List<Object> items

Tags:

java

jaxb

jaxb2

Does anybody know how to attach custom XmlAdapter to objects contained in heterogenous list (like List)? For example - suppose we have a container class with a list of miscelaneous objects:

@XmlRootElement(name = "container")
public class Container {
    private List<Object> values = new ArrayList<Object>();

    @XmlElement(name = "value")
    public List<Object> getValues() {
        return values;
    }

    public void setValues(List<Object> values) {
        this.values = values;
    }   
}

If we put String-s, Integer-s and so on they will be mapped by default. Now suppose we want to put a custom object:

public class MyObject {
    //some properties go here   
}

The obvious solution is to write a custom adapter:

public class MyObjectAdapter extends XmlAdapter<String, MyObject> {
    //marshalling/unmarshalling
}

But unfortunately it doesn't work with package-level @XmlJavaTypeAdapter - adapter just never called so marhalling fails. And I can't apply it to getValues() directly because there can be other types of objects. @XmlJavaTypeAdapter only works if I have a field of MyObject type in Container (also with package-level annotaton):

public class Container {
    private MyObject myObject;
}

But this is not what I want - I want a list of arbitrary objects. I'm using standard Sun's JAXB implementation:

<dependency>
    <groupId>com.sun.xml.bind</groupId>
    <artifactId>jaxb-impl</artifactId>
    <version>2.2.3-1</version>
</dependency>

Any ideas how to do the mapping?

P.S.: One small clarification - I'd like to avoid annotating MyObject with JAXB annotations. It may be a class from third-party library which is not under my control. So any changes should be outside of MyObject.

like image 402
Paul Lysak Avatar asked Mar 06 '13 16:03

Paul Lysak


1 Answers

You could try to change your MyObjectAdapter so that extends XmlAdapter<String, List<Object>>. So it should look something like this:

public class MyObjectAdapter extends XmlAdapter<String, List<Object>> {
    //marshalling/unmarshalling
}

When you also add a XmlJavaTypeAdapter annotation to the getter in your Container class, it should work.

@XmlRootElement(name = "container")
public class Container {
    private ArrayList<Object> values = new ArrayList<Object>();

    @XmlElement(name = "value")
    @XmlJavaTypeAdapter(MyObjectAdapter.class)
    public ArrayList<Object> getValues() {
        return values;
    }

    public void setValues(ArrayList<Object> values) {
        this.values = values;
    }   
}
like image 54
mvieghofer Avatar answered Oct 31 '22 03:10

mvieghofer