Jump to contentWelcome to Vionta.net
Xesta: Mapping collections of objects

Xml usually hold collections of elements, repeatitions of elements that we would naturally bind to java.util.List subclasses.

** Single and multiple collections** is an important concept for Xesta. Programming approaches tend to organize collections of similar elements in its own separated bags. This is not mandatory in Java, a subinstance of List can hold instances of different objects. This is not the usual practice. Generics and other bind or serialization tools tend to the "one bag for each object type" practice. In Xml, the element name and namespace is a primary source of information and as a consequence mixed types of elements and the ordering may be really significative. We call single collection mapping to the collections where we have only one type of child on the Java side, and multiple collections where we may map more than one object type on a java side for the same collection. Mind that using XPath we may wrap child elements from more than one element in a single Java collection and we could also take single types of java objects from an element with different child nodes. This is one of the main appealings from this technique, although it comes with a downside when we switch to serialzing.

Single Collections

Mapping a single collection is quite simple, and support several combinations:

  • Mapping the element name on the child side. This is probably one of the most intuitive ways. In this case we explore a Log Level document, the appender collection points the context of the element collection to the base of the document content ("../*"). There the class type guess can be taken from the List generics declaration.

@Bind(expression = "/*:configuration")public class LogLevel implements Serializable {

@Bind(expression = "../*")private ArrayList appender = new ArrayList();

In the Child Element class, we would be considering all the "appender" elements with any schema.

@Bind(expression="*:appender")public class Appender implements Serializable {

@Bind(expression = "@*:name",key=true)private String name;

@Bind(expression = "*:param/@value")private String level;

In this case, the context is pointed in the collection part and the element type on the child side.

  • Mapping the child element on the collection side. This is also a very simple approach. In the following example we would be defining the full route of a maven plugin element on the collection side. No separated context and element.

@Bind(expression = "/project")public class MavenProject implements Serializable {

@Bind(expression = "*:artifactId")private String artifactId;

@Bind(expression = "./reporting/plugins/plugin")private ArrayList plugins = new ArrayList();

On the child side we would not need to add anything at the class level, as the class type is especified using generics.

public class Plugin implements Serializable {

@Bind(expression="artifactId")private String id;

  • Mapping the element name on the child side. In this case we would have an annotation on the list element that states the context of the collection.

@Bind(expression = "../*")private ArrayList appender = new ArrayList();

On the child element side we would especify the element that should be binded to the pojo.

@Bind(expression="*:appender")public class Appender implements Serializable {

@Bind(expression = "@*:name",key=true)private String name;

@Bind(expression = "*:param/@value")private String level;...

The key atribute of the annotation states that the property value could be used as an identifier of the element. This is used in collections where we want to take into consideration moving elements, sorting, etc.

  • Providing the child class element. This is another possibility, reserved usually for the multielement collections, where we state the class names that should be inspected for element mappings.

@Bind(expression = "/*:configuration")public class LogLevel implements Serializable {

@Bind(expression = "../*", classNames = "net.vionta.xml.xesta.test.beansamples.log.Appender")private ArrayList appender = new ArrayList();...

Multiple Collections

Multiple collections are list of elements that may have more than one element child type. This is a less used practice on the Java enterprise but may make a lot of sense when working with Xml documents. Xml Element semantic and metadata capabilities enables some of the most complex and flexible use cases on data management, and the element name, schema, etc. may be used to carry significative information.

Multiple collections require that you add the child element class names to the list declaration

@Bind(expression="./:",classNames = {"net.vionta.xml.xesta.test.beansamples.list.salvora.neu1.Parameter.class","net.vionta.xml.xesta.test.beansamples.list.salvora.neu1.RequestParameter.class","net.vionta.xml.xesta.test.beansamples.list.salvora.neu1.PathParameter.class",})private ArrayList<? extends Serializable> parameters = new ArrayList();...

Where in the child objects the class mapping should state the Xml element to be mapped to each one.

@Bind(expression="/*:parameter")public class Parameter implements Serializable {

public Parameter() {}

@Bind(expression="@key")private String key;

@Bind(expression="@value")private String value;...