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.
This commit is contained in:
Michael Bayne
2019-12-17 13:39:22 -08:00
parent 9f0ade9db7
commit da7970e993
2 changed files with 53 additions and 5 deletions
@@ -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);
@@ -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);
}
}