Question

I'm wondering why generated (from xsd) getter for list has always null check:

public class Response {

    @XmlElement(type = Integer.class)
    protected List<Integer> integers;

    public List<Integer> getIntegers() {
        if (integers == null) {
            integers = new ArrayList<Integer>();
        }
        return this.integers;
    }
}

Question:

Why? What is the reason? Is there any good one?

I'm asking becouse in some cases this is not a good thing. And looks like there is no way to change this behavior.

Was it helpful?

Solution

After a bit of digging, the reason becomes clear. I generated some code with xjc and for a list property, it created this comment:

/**
 * Gets the value of the bars property.
 * 
 * <p>
 * This accessor method returns a reference to the live list,
 * not a snapshot. Therefore any modification you make to the
 * returned list will be present inside the JAXB object.
 * This is why there is not a <CODE>set</CODE> method for the bars property.
 * 
 * <p>
 * For example, to add a new item, do as follows:
 * <pre>
 *    getBars().add(newItem);
 * </pre>
 * 
 * 
 * <p>
 * Objects of the following type(s) are allowed in the list
 * {@link Bar }
 * 
 * 
 */

This makes their intent clear. They wanted it to be impossible to have a stale List from the object, so it always returns the live list rather than making a copy. This means that multiple calls to the getter (from different threads or different contexts, for example), will always be given references to the same in-memory object. Doing this, however, meant that they couldn't have a setter, or they'd break this contract -- Context A could set the value, and Context B would then have a stale reference to the old value, and have no way to know that it had been changed.

Since, because of that design decision, they couldn't have a setter, there needed to be some way to mutate the list if you needed to add or remove items. Otherwise, an initially null list would always be null forever (barring shenanigans with reflection). Thus, the only remaining way to allow that was to check for null in the getter, and lazy-initialize at that time. That meant that the scheme for replacing the entire list had to be

foo.getBars().clear();
foo.getBars().addAll(someList);

As for why they chose this design...there's no way for anybody outside that team to know the answer to that. However, it's generally a very good pattern to follow for most code anyway (it reduces coupling, and eliminates common error conditions that the compiler can't warn you about), so it's hard to make much of an argument against it. If it's really causing you trouble (and you haven't really shown how it is, other than the fact that some of your objects have empty lists after a copy operation instead of null ones), then the only advice I can give you is to either not use the code generator, or write an extension for xjc to make it do what you want. There may even be an existing extension for this. I don't know.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top