diff --git a/src/main/java/com/x5/template/Chunk.java b/src/main/java/com/x5/template/Chunk.java index 0ea1aa4..0ffa098 100644 --- a/src/main/java/com/x5/template/Chunk.java +++ b/src/main/java/com/x5/template/Chunk.java @@ -36,7 +36,7 @@ * set up replacement rules for those tags like so: * *
- * TemplateSet templates = getTemplates(); // defined elsewhere + * Theme templates = getTemplates(); // defined elsewhere * Chunk myChunk = templates.makeChunk("my_template"); * myChunk.set("my_tag","hello tag"); * System.out.print( myChunk.toString() ); @@ -48,9 +48,8 @@ * hash mark surrounded by curly brackets/braces. * *- * TemplateSet is handy if you have a folder with lots of html templates.
* Here's an even simpler example, where the template string is supplied
- * without using TemplateSet: + * without using a theme: * ** String templateBody = "Hello {$name}! Your balance is ${$balance}." @@ -91,9 +90,9 @@ ** A: No*. To keep things simple and reduce potential for confusion, Chunk
* does not auto-magically fill any tags based on naming conventions or
- * in-template directives. You must explicitly invoke the "include command:
+ * in-template directives. You must explicitly invoke the include command:
* - * bla bla bla {.include #myTemplate} foo foo foo + * bla bla bla {% include #myTemplate %} foo foo foo * ** Actually, this documentation is outdated, and several extensions to the
* original template syntax are now available: @@ -111,7 +110,7 @@ * Q: My final output says "infinite recursion detected." What gives? * *- * A: You did some variation of this: + * A: You tripped the recursion depth limit (17) or you did some variation of this: *
* TEMPLATE: * bla bla bla {$name} @@ -167,10 +166,9 @@ * Q: Are tag names and subtemplate names case sensitive? * *- * A: Yes. I prefer to use mixed case in {$tagNames} with first letter
- * lowercase. In my experience this aids readability since tags are similar
- * to java variables in concept and that is the java case convention for
- * variables. Similarly, I prefer lowercase with underscores for all
+ * A: Yes. I prefer to use snake case in {$tag_names} but be aware
+ * that {$tag} and {$Tag} and {$TAG} are three different values.
+ * Similarly, I prefer lowercase with underscores for all
* {#sub_template_names}{#} since templates tend to be defined within html
* files which are typically named in all lowercase. * @@ -245,7 +243,7 @@ * Updates: Chunk Documentation
* * @author Tom McClure - * @version 3.0.0 + * @version 3.0.1 */ public class Chunk implements Map@@ -253,7 +251,7 @@ public class Chunk implements Map public static final int HASH_THRESH = 8; public static final int DEPTH_LIMIT = 17; - public static final String VERSION = "3.0.0"; + public static final String VERSION = "3.0.1"; private static final String TRUE = "TRUE"; @@ -461,18 +459,7 @@ public void set(String tagName, Object tagValue, String ifNull) if (tagName == null) return; // ensure that tagValue is either a String or a Chunk (or some tabular data) if (tagValue != null) { - tagValue = coercePrimitivesToString(tagValue); - if (tagValue instanceof Chunk || tagValue instanceof TableData) { - // don't treat chunk or tabledata as a Map - } else if (tagValue instanceof Map) { - // great, a map! - } else if (!(tagValue instanceof String - || tagValue instanceof Snippet - || tagValue instanceof List - || tagValue instanceof Object[])) { - // force to map - tagValue = new ObjectDataMap(tagValue); - } + tagValue = coercePrimitivesToStringAndBoxAliens(tagValue); } if (tagValue == null) { tagValue = (ifNull == null) ? "NULL" : ifNull; @@ -1086,9 +1073,9 @@ protected Object _resolveTagValue(SnippetTag tag, int depth, boolean ignoreParen tagValue = null; } } - // convert primitives to string - if (!(tagValue instanceof String)) { - tagValue = coercePrimitivesToString(tagValue); + // convert primitives to string, box illegal aliens + if (tagValue != null && !(tagValue instanceof String)) { + tagValue = coercePrimitivesToStringAndBoxAliens(tagValue); } String filters = tag.getFilters(); @@ -1126,16 +1113,40 @@ protected Object _resolveTagValue(SnippetTag tag, int depth, boolean ignoreParen } } - // unbox and stringify primitive wrapper objects - private Object coercePrimitivesToString(Object o) + // unbox and stringify primitive wrapper objects, box any objects if not chunk-friendly + private Object coercePrimitivesToStringAndBoxAliens(Object o) { + if (o == null) return o; + if (o instanceof Boolean) { return ((Boolean)o).booleanValue() ? "TRUE" : null; } else if (o != null && ObjectDataMap.isWrapperType(o.getClass())) { return o.toString(); } else { + return boxIfAlienObject(o); + } + } + + private Object boxIfAlienObject(Object o) + { + if (o == null) return o; + + if (o instanceof Chunk || o instanceof TableData) { + // Chunk and TableData can be handled natively + return o; + } else if (o instanceof Map) { + // Map can be handled natively + return o; + } else if (o instanceof String + || o instanceof Snippet + || o instanceof List + || o instanceof Object[]) { + // can all be handled natively return o; } + + // unrecognized object. wrap inside map. + return new ObjectDataMap(o); } protected Object resolveTagValue(String tagName, int depth) @@ -1288,7 +1299,7 @@ public void setMultiple(Map rules) if (rules == null || rules.size() <= 0) return; Set keys = rules.keySet(); for (String tagName : keys) { - setOrDelete(tagName,rules.get(tagName)); + setOrDelete(tagName, rules.get(tagName)); } } diff --git a/src/main/java/com/x5/template/LoopTag.java b/src/main/java/com/x5/template/LoopTag.java index db311c8..5c4b97d 100644 --- a/src/main/java/com/x5/template/LoopTag.java +++ b/src/main/java/com/x5/template/LoopTag.java @@ -241,7 +241,7 @@ private TableData fetchData(String dataVar, String origin) data = new TableOfMaps(list); } else { // last-ditch effort to extract data, treat as POJOs - data = TableOfMaps.boxObjectList((List)dataStore); + data = TableOfMaps.boxCollection(list); } } } else if (dataStore instanceof Object[]) { @@ -252,8 +252,21 @@ private TableData fetchData(String dataVar, String origin) data = TableOfMaps.boxObjectArray((Object[])dataStore); } } else if (dataStore instanceof Map) { - Map object = (Map)dataStore; - data = new ObjectTable(object); + if (dataStore instanceof com.x5.util.ObjectDataMap) { + Object unwrapped = ((com.x5.util.ObjectDataMap)dataStore).unwrap(); + if (unwrapped instanceof java.util.Collection) { + data = TableOfMaps.boxCollection((java.util.Collection)unwrapped); + } else if (unwrapped instanceof java.util.Enumeration) { + data = TableOfMaps.boxEnumeration((java.util.Enumeration)unwrapped); + } else if (unwrapped instanceof java.util.Iterator) { + data = TableOfMaps.boxIterator((java.util.Iterator)unwrapped); + } + } + if (data == null) { + // Doesn't support traditional iteration. Loop over object's keys:values instead. + Map object = (Map)dataStore; + data = new ObjectTable(object); + } } // only loop if following pointer diff --git a/src/main/java/com/x5/template/TableOfMaps.java b/src/main/java/com/x5/template/TableOfMaps.java index 4bbe28f..e19e501 100644 --- a/src/main/java/com/x5/template/TableOfMaps.java +++ b/src/main/java/com/x5/template/TableOfMaps.java @@ -1,6 +1,8 @@ package com.x5.template; import java.util.ArrayList; +import java.util.Collection; +import java.util.Enumeration; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -79,13 +81,46 @@ static TableData boxObjectList(List dataStore) return null; } + return boxIterator(dataStore.iterator()); + } + + @SuppressWarnings("rawtypes") + static TableData boxEnumeration(Enumeration dataStore) + { + if (dataStore == null || !dataStore.hasMoreElements()) { + return null; + } + + // convert to list of POJOs + List