Question

Given a bean like this:

public class MyBean {
    private List<Something> things;

    private List<Something> internalGetThings() {
        if (things == null) {
            things = new ArrayList<Something>();
        }
        return things;
    }

    public Iterable<Something> getThings() {
        return <an immutable copy of internalGetThings()>;
    }

    public void setThings(List<Something> someThings) {
        things.clear();
        for (Something aThing : someThings) {
            addThing(aThing);
        }
    }

    public void addThing(Something aThing) {
        things.add(aThing);
        // Do some special stuff to aThing
    }
}

Using external mapping file, when I map like this:

<xml-element java-attribute="things" name="thing" type="com.myco.Something" container-type="java.util.ArrayList" /> 

It seems that each individual Something is being added to the MyBean by calling getThings().add(). That's a problem because getThings() returns an immutable copy of the list, which is lazily initialized. How can I configure mapping (I'm using an external mapping file, not annotations) so that MOXy uses setThings() or addThing() instead?

Was it helpful?

Solution 2

Given the reason in @Blaise's answer, it doesn't seem possible to have MOXy (or any JAXB implementation in general?) populate a lazily-initialized collection via a setter method on the collection. However, a combination of xml-accessor-type="FIELD" (or @XmlAccessorType if using annotations) and defining a JAXB unmarshal event callback will get the job done. In my afterUnmarshal() implementation I do the special work on Something instances that is done in addSomething().

private void afterUnmarshal(Unmarshaller, Object parent) {
    for (Something aThing : getSomethings()) {
        // Do special stuff on aThing
    }
}

Using FIELD access type gets JAXB/MOXy to directly inject the collection into the field, bypassing the getter. Then the call back cleans things up properly.

OTHER TIPS

Why Does JAXB/MOXy Check the Get Method for Collection First?

JAXB (JSR-222) implementations give you a chance to have your property be the List interface and still leverage the underlying List implementation that you choose to use. To accomplish this a JAXB implementation will call the get method to see if the List implementation has been initialized. It it has the List will be populated using the add method.

public List<String> getThings() {
    if(null == things) {
        things = new ArrayList<String>();
    }
    return things;
}
public List<String> getThings() {
    if(null == things) {
        things = new LinkedList<String>();
    }
    return things;
}

If you don't pre-initialize the List property then MOXy/JAXB will build an instance of the List (default is ArrayList) and set it on the object using the set method.

private List<Something> things; // Don't Initialize

public List<String> getThings() {
    return things;
}

public void setThings(List<String> things) {
    this.things = things;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top