Collections

J2XB Supports mapping Java collections to XML structures (sequence and list structures). At this time, J2XB supports the Java collection types of Array, List and Set. It also supports sorting the collection before it is written to XML. The Java Map types are not supported yet.

Note that any atomic or bean value is supported as collection item.

Default Collections Support

By default, a collection type (Array, List or Set) are mapped to an element with maxOccur=unbounded . The collections can be collections of atomic types (with validations or facets) or bean types.

For example, the default collection property mapping is

@MOProperty(xmlName = "first", xmlOrder = 1)
public List<Integer> getFirstCase() {...}

is mapped to the following XML Schema

<xs:element name="first" type="xs:int" minOccurs="0" maxOccurs="unbounded"/>

XML List Style

XML defines a list type as a sequence of values separated by spaces, which can appear as an XML element or an XML attribute. An XML list is supported only for XML simple types. Facets can be used with XML List only if the list is defined as a global XML simple type.

The XML list style supportes only XML simple types - that is, only atomic types. Bean values are not supported. Note that it is possible to map complex Java types as atomic by defining an appropriate MOPropertyEditor (see Types - Defining new Custom Types ).

A Java list can be mapped to an XML list style using the annotation @MOXmlListStyle on the property. For instance

@MOXmlListStyle
@MOProperty(xmlName = "first", xmlOrder = 1)
public List<Integer> getFirstCase() {...}

The corresponsing XML schema will then be

<xs:element name="second">
  <xs:simpleType>
    <xs:list>
      <xs:simpleType>
        <xs:restriction base="xs:int">
        </xs:restriction>
      </xs:simpleType>
    </xs:list>
  </xs:simpleType>
</xs:element>

When using facets (validations), the Java property definition can be

@MOProperty(xmlName = "ten", xmlOrder = 10)
@MOXmlListStyle
@MOXmlGlobalType("ListItem2List")
@MOXmlNamespaceRef(AtomicCollections.class)
@MOValidationCollection(min = 2, max = 4)
public List<ListItem2> getTenthCase() {...}

...

@MOXmlGlobalType("IntegerList")
@MOXmlNamespaceRef(AtomicCollections.class)
public enum ListItem2 {one, two, three, four, five, six, seven, eight, nine}

Note we must use the @MOXmlGlobalType annotation with the @MOValidationCollection and @MOXmlListStyle annotation combination. The corresponsing XML schema is

<xs:element name="ten">
  <xs:simpleType>
    <xs:restriction base="ns4:ListItem2List">
      <xs:minLength value="2"/>
      <xs:maxLength value="4"/>
    </xs:restriction>
  </xs:simpleType>
</xs:element>
...
<xs:simpleType name="ListItem2List">
  <xs:list itemType="ns4:IntegerList"/>
</xs:simpleType>
...
<xs:simpleType name="IntegerList">
  <xs:restriction base="xs:string">
    <xs:enumeration value="eight"/>
    <xs:enumeration value="nine"/>
    <xs:enumeration value="one"/>
    <xs:enumeration value="two"/>
    <xs:enumeration value="five"/>
    <xs:enumeration value="four"/>
    <xs:enumeration value="three"/>
    <xs:enumeration value="seven"/>
    <xs:enumeration value="six"/>
  </xs:restriction>
</xs:simpleType>

Collections Validations

XML Collections support two facets - minLength and maxLength . Those facets are supported using the @MOValidationCollection annotation (see the example in the previous section).

The @MOValidationCollection annotation can be used on any collection (Array, Set or List) with one exception - when mapping a list to an XML list style, unless the XML list is mapped as a global type, the @MOValidationCollection annotation cannot be used (due to a limitation of XML Shcema definitions).

Collection Sorting

In some cases the ordering of collection elements in the XML representation is important (the order of the elements has significance). However, when the ordering is not important for applicative reasons, it still may be important because of certain overheads.

For instance, an application that mappeds a class which has a Set is mapped to an XML representation. This XML representation is then stored in a source control system. While the ordering of the Set items is not important from an applicative point of view, the source control system has no knowladge of this and will mark the XML has changed anytime the items ordering has changed.

To solve this issue we have introduced the concept of ordering a collection before it is persisted to XML (there is no equivalent functionality when reading the XML file). By defualt collections are not sorted.

Sorting Atomic Collections

Sorting of Atomic collections is defined using the @MOCollectionSort annotation. The sorting is performed based on the natural ordering of the collection items, cased on the Java Comparable functionality. The sortByProperty member of the @MOCollectionSort should not be used.

@MOXmlListStyle
@MOProperty(xmlName = "first", xmlOrder = 1)
@MOCollectionSort()
public List<Integer> getFirstCase() {...}

Sorting Bean Collections

Sorting Bean collections is performed by sorting the beans based on a property of the collection item beans. For instance, in the following code fragment, the collection items are instances of the CardType class which has a property cardTypeName and the instances are sorted by this property value.

@MOProperty(xmlOrder = 2, xmlName = "cardTypes")
@MOCollectionSort(sortByProperty = "cardTypeName")
public List<CardType> getCards() {...}

Collection Custom Sorting (Atomic & Bean)

In case that the requirements for collection sorting are more complex, the @MOCollectionCustomSort annotation allows to define a callback that is responsible to sort the collection. The callback must implement the interface MOCollectionCustomSort.CustomSort .

For example, sorting the PortType instances using a callback PortsCustomSort

@MOProperty(xmlOrder = 2, xmlName = "portTypes")
@MOCollectionCustomSort(PortsCustomSort.class)
public Set<PortType> getPorts() {...}

and the callback definition is

public static class PortsCustomSort implements MOCollectionCustomSort.CustomSort {

  public <A> List<A> sort(Collection<A> collection) {
    List<PortType> list = new ArrayList<PortType>();
    for (A a: collection)
      list.add((PortType)a);
    Collections.sort(list, new Comparator<PortType>() {

      public int compare(PortType o1, PortType o2) {
        return o1.getTypeName().compareTo(o2.getTypeName());
      }
    });
    return (List<A>)list;
  }
}