diff --git a/src/main/java/com/samskivert/mustache/BasicCollector.java b/src/main/java/com/samskivert/mustache/BasicCollector.java index ab760ab..38e14a9 100644 --- a/src/main/java/com/samskivert/mustache/BasicCollector.java +++ b/src/main/java/com/samskivert/mustache/BasicCollector.java @@ -35,9 +35,6 @@ public abstract class BasicCollector implements Mustache.Collector } public Mustache.VariableFetcher createFetcher (Object ctx, String name) { - // support both .name and this.name to fetch members - if (name == Template.DOT_NAME || name == Template.THIS_NAME) return THIS_FETCHER; - if (ctx instanceof Map) return MAP_FETCHER; // if the name looks like a number, potentially use one of our 'indexing' fetchers @@ -73,7 +70,7 @@ public abstract class BasicCollector implements Mustache.Collector Map map = (Map)ctx; if (map.containsKey(name)) return map.get(name); // special case to allow map entry set to be iterated over - if (name == "entrySet") return map.entrySet(); + if ("entrySet".equals(name)) return map.entrySet(); return Template.NO_FETCHER_FOUND; } @Override public String toString () { @@ -113,15 +110,6 @@ public abstract class BasicCollector implements Mustache.Collector } }; - protected static final Mustache.VariableFetcher THIS_FETCHER = new Mustache.VariableFetcher() { - public Object get (Object ctx, String name) throws Exception { - return ctx; - } - @Override public String toString () { - return "THIS_FETCHER"; - } - }; - protected static abstract class ArrayHelper implements Mustache.VariableFetcher { public Object get (Object ctx, String name) throws Exception { try { diff --git a/src/main/java/com/samskivert/mustache/Mustache.java b/src/main/java/com/samskivert/mustache/Mustache.java index babc6f3..7a173b4 100644 --- a/src/main/java/com/samskivert/mustache/Mustache.java +++ b/src/main/java/com/samskivert/mustache/Mustache.java @@ -856,8 +856,10 @@ public class Mustache { @Override public void execute (Template tmpl, Template.Context ctx, Writer out) { Object value = tmpl.getValueOrDefault(ctx, _name, _line); if (value == null) { - throw new MustacheException.Context("No key, method or field with name '" + _name + - "' on line " + _line, _name, _line); + String msg = Template.isThisName(_name) ? + "Resolved '.' to null (which is disallowed), on line " + _line : + "No key, method or field with name '" + _name + "' on line " + _line; + throw new MustacheException.Context(msg, _name, _line); } write(out, _escaper.escape(_formatter.format(value))); } diff --git a/src/main/java/com/samskivert/mustache/Template.java b/src/main/java/com/samskivert/mustache/Template.java index 1099178..bae9935 100644 --- a/src/main/java/com/samskivert/mustache/Template.java +++ b/src/main/java/com/samskivert/mustache/Template.java @@ -240,7 +240,7 @@ public class Template { // if we reach here, we found nothing in this or our parent contexts... // if we have a compound key, decompose the value and resolve it step by step - if (name != DOT_NAME && name.indexOf(DOT_NAME) != -1) { + if (!name.equals(DOT_NAME) && name.indexOf(DOT_NAME) != -1) { return getCompoundValue(ctx, name, line, missingIsNull); } else { // otherwise let checkForMissing() decide what to do @@ -297,6 +297,11 @@ public class Template { } protected Object getValueIn (Object data, String name, int line) { + // if we're getting `.` or `this` then just return the whole context; we do this before the + // null check because it may be valid for the context to be null (if we're iterating over a + // list which contains nulls, for example) + if (isThisName(name)) return data; + if (data == null) { throw new NullPointerException( "Null context for variable '" + name + "' on line " + line); @@ -412,6 +417,10 @@ public class Template { } } + protected static boolean isThisName (String name) { + return DOT_NAME.equals(name) || THIS_NAME.equals(name); + } + protected static final String DOT_NAME = "."; protected static final String THIS_NAME = "this"; protected static final String FIRST_NAME = "-first"; diff --git a/src/test/java/com/samskivert/mustache/SharedTests.java b/src/test/java/com/samskivert/mustache/SharedTests.java index 8bd8a5b..c4b3cae 100644 --- a/src/test/java/com/samskivert/mustache/SharedTests.java +++ b/src/test/java/com/samskivert/mustache/SharedTests.java @@ -321,6 +321,12 @@ public abstract class SharedTests extends GWTTestCase execute(context("things", Arrays.asList("bar", "baz", "bif")))); } + @Test public void testNestedNullThis () { + check("bar!bif", Mustache.compiler().defaultValue("!"). + compile("{{#things}}{{.}}{{/things}}"). + execute(context("things", Arrays.asList("bar", null, "bif")))); + } + @Test public void testNewlineSkipping () { testNewlineSkipping("\n"); }