diff --git a/src/main/java/com/samskivert/mustache/DefaultCollector.java b/src/main/java/com/samskivert/mustache/DefaultCollector.java index 234b7a3..1753bad 100644 --- a/src/main/java/com/samskivert/mustache/DefaultCollector.java +++ b/src/main/java/com/samskivert/mustache/DefaultCollector.java @@ -17,6 +17,16 @@ import java.util.concurrent.ConcurrentHashMap; */ public class DefaultCollector extends BasicCollector { + private final boolean _allowAccessCoercion; + + public DefaultCollector () { + this(true); + } + + public DefaultCollector (boolean allowAccessCoercion) { + _allowAccessCoercion = allowAccessCoercion; + } + @Override public Mustache.VariableFetcher createFetcher (Object ctx, String name) { Mustache.VariableFetcher fetcher = super.createFetcher(ctx, name); @@ -63,10 +73,20 @@ public class DefaultCollector extends BasicCollector } protected Method getMethod (Class clazz, String name) { - // first check up the superclass chain - for (Class cc = clazz; cc != null && cc != Object.class; cc = cc.getSuperclass()) { - Method m = getMethodOn(cc, name); - if (m != null) return m; + if (_allowAccessCoercion) { + // first check up the superclass chain + for (Class cc = clazz; cc != null && cc != Object.class; cc = cc.getSuperclass()) { + Method m = getMethodOn(cc, name); + if (m != null) return m; + } + } else { + // if we only allow access to accessible methods, then we can just let the JVM handle + // searching superclasses for the method + try { + return clazz.getMethod(name); + } catch (Exception e) { + // fall through + } } return null; } @@ -119,11 +139,21 @@ public class DefaultCollector extends BasicCollector } private Method makeAccessible (Method m) { - if (!m.isAccessible()) m.setAccessible(true); + if (m.isAccessible()) return m; + else if (!_allowAccessCoercion) return null; + m.setAccessible(true); return m; } protected Field getField (Class clazz, String name) { + if (!_allowAccessCoercion) { + try { + return clazz.getField(name); + } catch (Exception e) { + return null; + } + } + Field f; try { f = clazz.getDeclaredField(name); diff --git a/src/test/java/com/samskivert/mustache/MustacheTest.java b/src/test/java/com/samskivert/mustache/MustacheTest.java index 80e776d..cb1b208 100644 --- a/src/test/java/com/samskivert/mustache/MustacheTest.java +++ b/src/test/java/com/samskivert/mustache/MustacheTest.java @@ -275,4 +275,22 @@ public class MustacheTest extends SharedTests test("k1v1k2v2", "{{#map.entrySet}}{{key}}{{value}}{{/map.entrySet}}", context("map", data)); } + + @Test public void testNoAccesCoercion () { + Object ctx = new Object() { + public Object foo () { + return new Object() { + public Object bar = new Object() { + public String baz = "hello"; + private String quux = "hello"; + }; + }; + } + }; + test("hello:hello", "{{foo.bar.baz}}:{{foo.bar.quux}}", ctx); + Mustache.Compiler comp = Mustache.compiler(). + withCollector(new DefaultCollector(false)). + defaultValue("missing"); + test(comp, "hello:missing", "{{foo.bar.baz}}:{{foo.bar.quux}}", ctx); + } }