2

I have a class that I wish to populate with content from an XML file using JAXB. My XML file looks similar to this:

<root>
  <mylist>
    <item id="1">First Item</item>
    <item id="2">Second Item</item>
  </mylist>
</root>

My JAXB annotated classes look like:

@XmlRootElement
class MyParentClass {

  // I always populate this with a TreeSet
  private Set<MyFieldItem> items;

  public void setItems(Set<MyFieldItem> items) {
    this.items = items;
  }

  @XmlElementWrapper("mylist") @XmlElement("item")
  public Set<MyFieldItem> getItems() {
    return items;
  }
}

class MyFieldItem implements Comparable<MyFieldItem> {
  private Integer id;
  private String value;

  public void setId(Integer id) {
    this.id = id;
  }

  @XmlAttribute
  public Integer getId() {
    return id;
  }

  public void setValue(String value) {
    this.value = value;
  }

  @XmlValue
  public String getValue() {
    return value;
  }

  public int compareTo(MyfieldItem o) {
    return this.id.compareTo(o.getId());
  }
}

I find that this arrangement serialises my objects to XML correctly, but when I try to convert it back the TreeSet I use becomes a HashSet.

In theory my collection could be fixed to a TreeSet (which does fix the problem), but I'd rather configure JAXB correctly and defer that logic elsewhere. How do I tell JAXB to build a TreeSet instead?

seanhodges
  • 17,426
  • 15
  • 71
  • 93
  • I partially answered my own question whilst writing it up: Since I need to preserve the natural ordering of my set, it really should have been a SortedSet in the first place. I changed this and the unmarshalling is working correctly now. I'd still like to hear any thoughts on my setup, in particular I'd rather dictate the implementation JAXB is picking, rather than rely on magic... – seanhodges Aug 18 '11 at 09:13

1 Answers1

3

The easiest way to solve this problem is pre-initialize your Set property to the appropriate implementation type, and your JAXB implmentation (Metro, EclipseLink MOXy, Apache JaxMe, etc) will use that instead of creating a new Set:

package forum7104810;

import java.util.Set;
import java.util.TreeSet;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name="root")
class MyParentClass {

  // Initialize this property with an instance of the desired type.
  private Set<MyFieldItem> items = new TreeSet<MyFieldItem>();

  public void setItems(Set<MyFieldItem> items) {
    this.items = items;
  }

  @XmlElementWrapper(name="mylist") 
  @XmlElement(name="item")
  public Set<MyFieldItem> getItems() {
    return items;
  }

}

For More Information

seanhodges
  • 17,426
  • 15
  • 71
  • 93
bdoughan
  • 147,609
  • 23
  • 300
  • 400
  • I'll try this tonight, it sounds like a pretty elegant solution if it works. – seanhodges Aug 18 '11 at 14:53
  • 1
    It will definitely work, for more information see: http://blog.bdoughan.com/2011/01/jaxb-and-choosing-list-implementation.html – bdoughan Aug 18 '11 at 15:05
  • This worked, although I opted for defining the field as a SortedSet instead, which had the same effect. Thanks for your help! – seanhodges Aug 19 '11 at 11:00