Location Tracking

Starting with Modello 1.4, some parsers (currently only XPP3) support the tracking of line/column information for the input data. This means that additional metadata is stored in the model that can be used to query the location of some model element in the input source, e.g. for means of better error reporting to the user.

To store the line/column information, one class of the model has to be specifically attributed:

<class locationTracker="locations" java.clone="shallow">
  <name>Location</name>
  <version>1.0.0+</version>
  <fields>
    <!-- line and column fields are auto-generated by Modello -->
  </fields>
</class>

The attribute locationTracker in the snippet above signals to Modello that this class should be used to record line/column metadata during parsing. The class can be modelled as usual but the fields to save the line and column number along with their accessors are automatically generated by Modello.

All other model classes will be equipped with a field to hold instances of the Location class and accessors to query them. This way, each model class keeps track of the input locations for its fields:

public class Model
{

    private Map<Object, Location> locations;

    public Location getLocation( Object field )
    {
        return ( locations != null ) ? locations.get( field ) : null;
    }

    [...]

}

The location map shown above is keyed by field name. An empty string is used to query the location of the bean itself (or its text contents). For collections or maps, the returned Location instance can be further queried for its items. The key to query an item depends on the type of collection. For lists the zero-based index is used, for sets the item itself is used and for maps/properties the mapping key is used. For example, consider this input XML:

<model>
  <someString>hello</someString>
  <listItems>
    <listItem>list</listItem>
  </listItems>
  <setItems>
    <setItem>set</setItem>
  </setItems>
  <properties>
    <key>value</key>
  </properties>
</model>

For this data model, one could query the location metadata like this (neglecting null checking):

Model model = <parser invocation>;

// to query the location of the <model> element itself
Location location1 = model.getLocation( "" );

// to query the location of the contents of <someString>, i.e. "hello"
Location location2 = model.getLocation( "someString" );

// to query the location of the first list item, i.e. "list"
Location location3 = model.getLocation( "listItems" ).getLocation( Integer.valueOf( 0 ) );

// to query the location of the set item, i.e. "set"
Location location4 = model.getLocation( "setItems" ).getLocation( "set" );

// to query the location of the properties data, i.e. "value"
Location location5 = model.getLocation( "properties" ).getLocation( "key" );

For performance reasons, generation of location metadata during parsing has to be explicitly requested. Usually, this means to use an extended reader instead of the normal reader generated by Modello.

Occasionally, just tracking the line/column number is not enough but the input file of the model needs to be recorded as well. For this reason, another class of the model can be marked as a source tracker:

<class sourceTracker="source">
  <name>Source</name>
  <version>1.0.0+</version>
  <fields>
    <!-- modelled by end-user, e.g. fields to hold pathname/URL etc. -->
  </fields>
</class>

The fields of this source tracking class are entirely up to the application, Modello will merely extend the generated Location class to support a reference to the Source class. An instance of the source tracking class can be provided to the extended readers which will then use it to populate all the generated Location instances.