From da7970e993eeb057864f205814cde05f718337b8 Mon Sep 17 00:00:00 2001 From: Michael Bayne Date: Tue, 17 Dec 2019 13:39:22 -0800 Subject: [PATCH] Allow access coercion to be disabled. I'm not disabling it by default because that would change behavior for anyone who was using reflection, which seems like annoying breakage. People who are using JMustache with Java 9 can configure a non-coercing DefaultCollector to eliminate the illegal access warnings. --- .../samskivert/mustache/DefaultCollector.java | 40 ++++++++++++++++--- .../com/samskivert/mustache/MustacheTest.java | 18 +++++++++ 2 files changed, 53 insertions(+), 5 deletions(-) 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); + } }