public class ObjectMap<T>
extends java.util.AbstractMap<java.lang.Object,java.lang.Object>
The class extends the Java Map. The map values are the data items from the parsed input which can thus be accessed directly by name from a StringTemplate V4 template, by using separating dots similar to the notation of fields in Java objects.
Most objects of the data model are instances of this kind of container. The idea is to
access the data items in the container under their natural name. As an example, if the
container is the representation of an Excel workbook then the principal data items are
the worksheets of that book and they could be accessed by name. Be the workbook "myBook"
and have it two worksheets, named "mySheetA" and "mySheetB". From a StringTemplate V4
template one could access the parsed data like <myBook.mySheetA> or <myBook.mySheetB>.
This way to access dynamic data (the names of the "fields" of myBook are
determined by the application input) is convenient and in the template syntactically
very close to the conventional StringTemplate data model, which is a predefined Java
data structure consisting of nested Java classes having public fields of predefined
names. In either case the dot notation is used in the template.
The major difference between this container class and the conventional data model is the inaccessibility of additional public fields. For map objects the StringTemplate V4 template engine only supports the map lookup but not the "normal" introspection for public fields of requested name. If we extend the container with public fields, e.g. we want to add the field "noSheets" to our workbook, then this field would not be visible from a template. We support such fields by mapping them into the map's contents. The Java Map implementation is overridden to do so. Now all access from the template engine is done via the map interface, be it access of predefined fields like our example "noSheets" or be it access of true, dynamic contents, i.e. data items like "mySheetA" or "mySheetB". We call the predefined fields "pseudo-fields" since from a template they look like and behave like true public fields of the Java object but in fact they are implemented as map content items.
This class implements a map, which supports true map behavior (dynamic data items from the application input) and having predefined pseudo-fields (predefined by our application design), that are merged into the map contents. Some generic pseudo-fields are already defined by this base class (e.g. the name of the container) and it provides the mechanisms to let a derived class define its own, further pseudo-fields.
Two problems arise.
Evidently, pseudo-fields and true, dynamic data contents share the map key space. All
keys are Java String objects with the meaning name-of-object. The name under which a
pseudo-field is stored and accessed cannot be used for a dynamic data item at the same
time. Since we have the pseudo-field "name_" there can't be a worksheet called name_ in the workbook myBook in our example above. From a template <myBook.name_> refers to the name of myBook but not to a worksheet of that
name.
The implementation of this map class checks for name clashes of this kind at parse time, when the map is filled with the information from the application input.
It is impossible to complete parsing if there's such a name clash. Since naming of data items can be controlled via command line options this will not mean that it would be impossible to successfully read the input, only some fine tuning of the application configuration will be required.
In practice, name clashes will occur only exceptional. Typical names of pseudo-fields
in the data model will not likely appear in natural Excel input. Where this is not the
case we decided to rename our pseudo-fields, even if this leads to less neat template
code. The most prominent example is the name of an object. In the conventional data
model this is the public field name. Since "name" can easily appear in natural
input we called the pseudo-field "name_". The same happens for the index-in-collection,
our conventional "i" and "i0" became "i_" and "i0_", respectively.
The second problem is the documentation. Conventional data models, which are predefined, nested Java classes are appropriately documented with Javadoc. All public fields are listed and explained in meaningful HTML representation and their nesting is easily understandable. Using this container class the pseudo-fields are implemented by run-time code and won't appear as such in the Javadoc documentation.
At several points the design of the implementation of this map class was driven by
considerations how to make information important to StringTemplate V4 template writers
visible in the Javadoc documentation. First of all, the pseudo-fields are held in true
fields. These are inaccessible via the template engine and not required by surrounding
Java code. Under normal circumstances these fields would be implemented private. We made
them public so that the application user will find them in Javadoc. The user sees these
fields as public - and can indeed access them (if not as public fields but via the map
interface as pseudo-field). Secondary, all pseudo-fields are listed as a Java
enumeration. For this base class and for each derived container class you will find the
related enumeration and each named value will be documented with a short explanation of
the pseudo-field it relates to. See e.g. Cluster.PseudoFieldName or ObjectMap.PseudoFieldName.
| Modifier and Type | Class and Description |
|---|---|
static class |
ObjectMap.PseudoFieldName
This is the list of pseudo-fields of class
ObjectMap that can be accessed
from a StringTemplate V4 template. |
| Modifier and Type | Field and Description |
|---|---|
boolean |
exists
The presence of a container object as Boolean.
|
int |
i_
The one based index of the object in a collection of those.
|
int |
i0_
The null based index of the object in a collection of those.
|
ObjectList<T> |
itemAry
All real data items (in contrast to the pseudo-fields), which are held in the map
itemMap are stored a second time in this list. |
java.util.Map<java.lang.String,T> |
itemMap
This is an embedded map, which stores all real data items (in contrast to the
pseudo-fields).
|
Identifier |
name_
The name of the object.
|
int |
objId
The ID of this object.
|
| Modifier and Type | Method and Description |
|---|---|
boolean |
containsKey(java.lang.Object key)
Check for presence of a given key,value pair in the map.
|
static <T> SortOrder.Comparator<ObjectMap<T>> |
createComparator(SortOrder.Order sortOrder)
A comparator for sorting containers in a Java List is created and returned.
|
java.util.Set<java.util.Map.Entry<java.lang.Object,java.lang.Object>> |
entrySet()
Deriving a new Map class from AbstractMap requires at minimum overloading the
entrySet function.
|
java.lang.Object |
get(java.lang.Object key)
Get an object from the Map as it is seen by the StringTemplate V4 engine.
|
int |
getNoItems()
|
java.lang.Object |
put(java.lang.Object key,
java.lang.Object value)
Adding a real data item to this map object must only be done using
putItem(java.lang.String, T). |
boolean |
putItem(java.lang.String objectName,
T object)
Add a real data item to the map.
|
void |
setIndexInCollection(int i0)
Set the index-in-collection.
|
java.lang.String |
toString()
Get the string representation of the map object; it's its name as an identifier.
|
public final int objId
public Identifier name_
Identifier. If is is
rendered like <obj.name_> in a StringTemplate V4 template you will not get
the given name but the C identifier, which is most similar to the given name - this
can even be identical to the name. If you really want to get the given name then
you'd rather put <obj.name_.givenName> into your template.For consistency, this field would be better named "name" (compare to other elements of the data model). However, all public field names of this class are reserved key words at the same time and can't be used as designations in the application input. Therefore, we can't apply such a common designation as "name".
public int i0_
i0 for consistency with our usual data
model naming scheme. However, all public field names of this class are
reserved key words at the same time and can't be used as designations in the
application input. Therefore, we can't apply such a common designation as "i0".public int i_
The value of this index is i0_ + 1.
i for consistency with our usual data
model naming scheme. However, all public field names of this class are
reserved key words at the same time and can't be used as designations in the
application input. Therefore, we can't apply such a common designation as "i"public final java.util.Map<java.lang.String,T> itemMap
Cluster: Data items are ExcelWorkbook objects
ExcelWorkbook: Data items are ExcelWorksheet objects
ExcelWorksheet: Data items are RowObjectContainer objects, the
groups of row objects
RowObjectContainer: Recursively contains data items of same type. This
model the recursive grouping of row objects
RowObject: Data items are CellObject objectspublic ObjectList<T> itemAry
itemMap are stored a second time in this list.ObjectList.sortOrder. From a
StringTemplate V4 template the sort order can be queried with an expression like
<obj.itemAry.sortOrder>.public final boolean exists
<if(cluster.object)>"object" is present<endif>
will this fail for Java Map objects. <if(cluster.mapObject)> will return
false even if the map object exists but if it is empty. Empty maps are
however quite common in our data model. Let's take for example a flat worksheet
"mySheet" of workbook "myBook" that owns all row objects in the root level and
doesn't have nested sub-groups of row objects. The template expression
<if(myBook.mySheet)><myBook.mySheet.rowAry:renderRow()><endif>
would fail and not render any row object. (Since the map mySheet is
empty.) Using the flag exists the template can be formulated meaningful and
safe:
<if(myBook.mySheet.exists)><myBook.mySheet.rowAry:renderRow()><endif>
public int getNoItems()
public void setIndexInCollection(int i0)
i0 - The new value for the null based index of this object in an embedding collection.public java.util.Set<java.util.Map.Entry<java.lang.Object,java.lang.Object>> entrySet()
We overload this method to filter out the pseudo fields, we want to hide when an iteration along all map entries takes place. Filtering the pseudo fields here is a contradictory behavior with the overloaded get method, which will return the pseudo fields. Theoretically, this contradiction could be recognized by the StringTemplate V4 engine but by experience it doesn't complain about.
entrySet in interface java.util.Map<java.lang.Object,java.lang.Object>entrySet in class java.util.AbstractMap<java.lang.Object,java.lang.Object>public boolean containsKey(java.lang.Object key)
The StringTemplate V4 engine will use this Map method prior to the query for the value. We say "is available" to both, contained real data items and pseudo fields. This is a contradictory behavior with the behavior of method entrySet, which won't list the pseudo fields. Theoretically, the contradiction could be recognized by the StringTemplate V4 engine but by experience it doesn't complain about.
There's a pit-fall: The template engine has a two step approach to find the map
entries. First, it tries to identify the entry by passing in the template attribute,
which is used in the template map operator .(). The attribute is represented
in the StringTemplate defined Java class; different template constructs will yield
different Java classes. If the engine gets a negative response then it tries again,
this time with the attribute rendered as text, as a Java String object. (If the
internal attribute representation already is a Java String then no second attempt is
made.)
For us, it's impossible to operate on the internal StringTemplate classes. Therefore we reject all queries with key objects, which are not of Java class String and wait for the second attempt.
containsKey in interface java.util.Map<java.lang.Object,java.lang.Object>containsKey in class java.util.AbstractMap<java.lang.Object,java.lang.Object>key - The key attribute from the template.true for contained real data items and pseudo fields if referenced to by
Java String keys, false otherwise.public java.lang.Object get(java.lang.Object key)
get in interface java.util.Map<java.lang.Object,java.lang.Object>get in class java.util.AbstractMap<java.lang.Object,java.lang.Object>key - The key, which the demanded object is associated with. In practice and due to the
behavior of the StringTemplate V4 engine this will always be a Java String. This
type is ensured by assertion. See method containsKey(java.lang.Object), too.public java.lang.Object put(java.lang.Object key,
java.lang.Object value)
putItem(java.lang.String, T). Java's Map.put(K, V) is overridden only to double-check this by
assertion.put in interface java.util.Map<java.lang.Object,java.lang.Object>put in class java.util.AbstractMap<java.lang.Object,java.lang.Object>key - The name of the object.value - The added object of template type public boolean putItem(java.lang.String objectName,
T object)
objectName - This is the name under which the object is stored in the map. Must not be null.object - The object to add. Must not be null.public static <T> SortOrder.Comparator<ObjectMap<T>> createComparator(SortOrder.Order sortOrder)
sortOrder - The wanted sort order. Sorting is done with respect to the name name_ of
the container. Sorting is done based on SortOrder.createComparatorString(excelExporter.excelParser.SortOrder.Order);
refer to this method to get details about the behavior of sorting.public java.lang.String toString()
<obj.name_>.toString in class java.util.AbstractMap<java.lang.Object,java.lang.Object>