Problems with Defensive Collection Getters and JAXB

1:28 PM , , 1 Comments

A good general practice with collection getters is that they a) return a reference to the collection or b) return an unmodifiable wrapper around the collection. Further, it's often desirable to have an addXXX and removeXXX instead of a collection setter to complete the encapsulation picture.



public class Order {
private List items;

public List getItems() {
Collections.unmodifiableList(items);
}

// .. no setter

public void addItem(Item item) {
items.add(item);
}

public void removeItem(Item item) {
items.remove(item);
}
}

This practice runs awry when using this object for marshalling XML with JAXB. What you will notice when it tries to unmarshal and XML message representing this object is that the resulting items list will be empty.

That's really too bad.

What is happening is that JAXB in the absence of a collection setter is calling the getter in the hopes of calling "add" on the reference that it gets back. Unfortunately, since we are returning an unmodifiable list, JAXB silently fails by not adding any items at all and moving on.

The solution is actually pretty simple. We just need to tell JAXB to look at the field instead of the method. You do this with two annotations:

public class Order {
@XmlElementWrapper("items") @XmlElement("item") private List items;

...
}

And that's all! Now, you can keep your defensive collection encapsulation and still allow JAXB to do it's unmarshalling. Enjoy!

Josh Cummings

"I love to teach, as a painter loves to paint, as a singer loves to sing, as a musician loves to play" - William Lyon Phelps

1 comment:

  1. Thanks, this helped me simplify my REST service using JAXB with Jersey

    ReplyDelete