This is an automated email from the ASF dual-hosted git repository.
ddekany pushed a commit to branch 2.3-gae
in repository https://gitbox.apache.org/repos/asf/freemarker.git
The following commit(s) were added to refs/heads/2.3-gae by this push:
new f13ef35 MemberAccessPolicy now also covers the special case when
toString() is called to convert and object to string in a template. This was
added as toString() might shows information that you don't want to be exposed.
f13ef35 is described below
commit f13ef351818acc26d067e295234153f48c13b161
Author: ddekany <[email protected]>
AuthorDate: Tue Jan 14 16:56:50 2020 +0100
MemberAccessPolicy now also covers the special case when toString() is
called to convert and object to string in a template. This was added as
toString() might shows information that you don't want to be exposed.
---
.../ext/beans/AllowAllMemberAccessPolicy.java | 5 ++
.../ext/beans/BlacklistMemberAccessPolicy.java | 18 +++++
.../freemarker/ext/beans/ClassIntrospector.java | 35 ++++++++--
.../ext/beans/DefaultMemberAccessPolicy.java | 10 +++
.../ext/beans/LegacyDefaultMemberAccessPolicy.java | 5 ++
.../freemarker/ext/beans/MemberAccessPolicy.java | 10 +++
.../java/freemarker/ext/beans/StaticModel.java | 2 +-
.../java/freemarker/ext/beans/StringModel.java | 9 ++-
.../ext/beans/WhitelistMemberAccessPolicy.java | 18 +++++
.../ext/beans/DefaultMemberAccessPolicyTest.java | 6 ++
...DefaultObjectWrapperMemberAccessPolicyTest.java | 81 ++++++++++++++++++++++
.../MemberSelectorListMemberAccessPolicyTest.java | 45 +++++++++++-
12 files changed, 235 insertions(+), 9 deletions(-)
diff --git a/src/main/java/freemarker/ext/beans/AllowAllMemberAccessPolicy.java
b/src/main/java/freemarker/ext/beans/AllowAllMemberAccessPolicy.java
index dd9a1fc..5b6284f 100644
--- a/src/main/java/freemarker/ext/beans/AllowAllMemberAccessPolicy.java
+++ b/src/main/java/freemarker/ext/beans/AllowAllMemberAccessPolicy.java
@@ -50,4 +50,9 @@ final class AllowAllMemberAccessPolicy implements
MemberAccessPolicy {
public ClassMemberAccessPolicy forClass(Class<?> contextClass) {
return CLASS_POLICY_INSTANCE;
}
+
+ @Override
+ public boolean isToStringAlwaysExposed() {
+ return true;
+ }
}
diff --git
a/src/main/java/freemarker/ext/beans/BlacklistMemberAccessPolicy.java
b/src/main/java/freemarker/ext/beans/BlacklistMemberAccessPolicy.java
index 69d0410..9c86e1b 100644
--- a/src/main/java/freemarker/ext/beans/BlacklistMemberAccessPolicy.java
+++ b/src/main/java/freemarker/ext/beans/BlacklistMemberAccessPolicy.java
@@ -19,6 +19,7 @@
package freemarker.ext.beans;
+import java.lang.reflect.Method;
import java.util.Collection;
/**
@@ -38,6 +39,8 @@ import java.util.Collection;
*/
public class BlacklistMemberAccessPolicy extends
MemberSelectorListMemberAccessPolicy {
+ private final boolean toStringAlwaysExposed;
+
/**
* @param memberSelectors
* List of member selectors; see {@link
MemberSelectorListMemberAccessPolicy} class-level documentation for
@@ -45,6 +48,21 @@ public class BlacklistMemberAccessPolicy extends
MemberSelectorListMemberAccessP
*/
public BlacklistMemberAccessPolicy(Collection<? extends MemberSelector>
memberSelectors) {
super(memberSelectors, ListType.BLACKLIST, null);
+
+ boolean toStringBlacklistedAnywhere = false;
+ for (MemberSelector memberSelector : memberSelectors) {
+ Method method = memberSelector.getMethod();
+ if (method != null && method.getName().equals("toString") &&
method.getParameterTypes().length == 0) {
+ toStringBlacklistedAnywhere = true;
+ break;
+ }
+ }
+ toStringAlwaysExposed = !toStringBlacklistedAnywhere;
+ }
+
+ @Override
+ public boolean isToStringAlwaysExposed() {
+ return toStringAlwaysExposed;
}
}
diff --git a/src/main/java/freemarker/ext/beans/ClassIntrospector.java
b/src/main/java/freemarker/ext/beans/ClassIntrospector.java
index aa3bafb..e92226d 100644
--- a/src/main/java/freemarker/ext/beans/ClassIntrospector.java
+++ b/src/main/java/freemarker/ext/beans/ClassIntrospector.java
@@ -82,6 +82,8 @@ class ClassIntrospector {
new ExecutableMemberSignature("get", new Class[] { String.class });
private static final ExecutableMemberSignature GET_OBJECT_SIGNATURE =
new ExecutableMemberSignature("get", new Class[] { Object.class });
+ private static final ExecutableMemberSignature TO_STRING_SIGNATURE =
+ new ExecutableMemberSignature("toString", new Class[0]);
/**
* When this property is true, some things are stricter. This is mostly to
catch suspicious things in development
@@ -136,6 +138,8 @@ class ClassIntrospector {
static final Object CONSTRUCTORS_KEY = new Object();
/** Key in the class info Map to the get(String|Object) Method */
static final Object GENERIC_GET_KEY = new Object();
+ /** Key in the class info Map to the toString() Method */
+ static final Object TO_STRING_HIDDEN_FLAG_KEY = new Object();
//
-----------------------------------------------------------------------------------------------------------------
// Introspection configuration properties:
@@ -272,7 +276,8 @@ class ClassIntrospector {
*/
private Map<Object, Object> createClassIntrospectionData(Class<?> clazz) {
final Map<Object, Object> introspData = new HashMap<Object, Object>();
- ClassMemberAccessPolicy effClassMemberAccessPolicy =
getEffectiveClassMemberAccessPolicy(clazz);
+ MemberAccessPolicy effMemberAccessPolicy =
getEffectiveMemberAccessPolicy();
+ ClassMemberAccessPolicy effClassMemberAccessPolicy =
effMemberAccessPolicy.forClass(clazz);
if (exposeFields) {
addFieldsToClassIntrospectionData(introspData, clazz,
effClassMemberAccessPolicy);
@@ -280,6 +285,10 @@ class ClassIntrospector {
final Map<ExecutableMemberSignature, List<Method>> accessibleMethods =
discoverAccessibleMethods(clazz);
+ if (!effMemberAccessPolicy.isToStringAlwaysExposed()) {
+ addToStringHiddenFlagToClassIntrospectionData(introspData,
accessibleMethods, effClassMemberAccessPolicy);
+ }
+
addGenericGetToClassIntrospectionData(introspData, accessibleMethods,
effClassMemberAccessPolicy);
if (exposureLevel != BeansWrapper.EXPOSE_NOTHING) {
@@ -705,6 +714,19 @@ class ClassIntrospector {
}
}
+ private void addToStringHiddenFlagToClassIntrospectionData(Map<Object,
Object> introspData,
+ Map<ExecutableMemberSignature, List<Method>> accessibleMethods,
+ ClassMemberAccessPolicy effClassMemberAccessPolicy) {
+ Method toStringMethod = getFirstAccessibleMethod(TO_STRING_SIGNATURE,
accessibleMethods);
+ if (toStringMethod == null) {
+ throw new BugException("toString() method not found");
+ }
+ // toString() is pretty much always exposed, so we make the negative
case to take extra memory:
+ if (!effClassMemberAccessPolicy.isMethodExposed(toStringMethod)) {
+ introspData.put(TO_STRING_HIDDEN_FLAG_KEY, true);
+ }
+ }
+
private void addConstructorsToClassIntrospectionData(final Map<Object,
Object> introspData,
Class<?> clazz, ClassMemberAccessPolicy
effClassMemberAccessPolicy) {
try {
@@ -828,12 +850,13 @@ class ClassIntrospector {
}
/**
- * Returns the {@link ClassMemberAccessPolicy} to actually use, which is
not just
- * {@link BeansWrapper#getMemberAccessPolicy()} if {@link
BeansWrapper#getExposureLevel()} is more allowing than
- * {@link BeansWrapper#EXPOSE_SAFE}. {@link BeansWrapper#EXPOSE_NOTHING}
though is not factored in here.
+ * Returns the {@link MemberAccessPolicy} to actually use, which is not
just
+ * {@link BeansWrapper#getMemberAccessPolicy()} if {@link
BeansWrapper#getExposureLevel()} is more
+ * allowing than {@link BeansWrapper#EXPOSE_SAFE}. {@link
BeansWrapper#EXPOSE_NOTHING} though is
+ * not factored in here.
*/
- ClassMemberAccessPolicy getEffectiveClassMemberAccessPolicy(Class<?>
containingClass) {
- return exposureLevel < BeansWrapper.EXPOSE_SAFE ?
AllowAllMemberAccessPolicy.CLASS_POLICY_INSTANCE :
memberAccessPolicy.forClass(containingClass);
+ MemberAccessPolicy getEffectiveMemberAccessPolicy() {
+ return exposureLevel < BeansWrapper.EXPOSE_SAFE ?
AllowAllMemberAccessPolicy.INSTANCE : memberAccessPolicy;
}
private boolean is2321Bugfixed() {
diff --git a/src/main/java/freemarker/ext/beans/DefaultMemberAccessPolicy.java
b/src/main/java/freemarker/ext/beans/DefaultMemberAccessPolicy.java
index 71067c9..bc8b6d8 100644
--- a/src/main/java/freemarker/ext/beans/DefaultMemberAccessPolicy.java
+++ b/src/main/java/freemarker/ext/beans/DefaultMemberAccessPolicy.java
@@ -50,6 +50,7 @@ public final class DefaultMemberAccessPolicy implements
MemberAccessPolicy {
private final Set<Class<?>> whitelistRuleNonFinalClasses;
private final WhitelistMemberAccessPolicy whitelistMemberAccessPolicy;
private final BlacklistMemberAccessPolicy blacklistMemberAccessPolicy;
+ private final boolean toStringAlwaysExposed;
/**
* Returns the singleton that's compatible with the given incompatible
improvements version.
@@ -147,6 +148,10 @@ public final class DefaultMemberAccessPolicy implements
MemberAccessPolicy {
}
}
blacklistMemberAccessPolicy = new
BlacklistMemberAccessPolicy(blacklistMemberSelectors);
+
+ toStringAlwaysExposed =
+ whitelistMemberAccessPolicy.isToStringAlwaysExposed()
+ && blacklistMemberAccessPolicy.isToStringAlwaysExposed();
} catch (Exception e) {
throw new IllegalStateException("Couldn't init " +
this.getClass().getName() + " instance", e);
}
@@ -179,6 +184,11 @@ public final class DefaultMemberAccessPolicy implements
MemberAccessPolicy {
}
}
+ @Override
+ public boolean isToStringAlwaysExposed() {
+ return toStringAlwaysExposed;
+ }
+
private boolean isTypeWithWhitelistRule(Class<?> contextClass) {
if (whitelistRuleFinalClasses.contains(contextClass)) {
return true;
diff --git
a/src/main/java/freemarker/ext/beans/LegacyDefaultMemberAccessPolicy.java
b/src/main/java/freemarker/ext/beans/LegacyDefaultMemberAccessPolicy.java
index 13b6c41..08c7c8f 100644
--- a/src/main/java/freemarker/ext/beans/LegacyDefaultMemberAccessPolicy.java
+++ b/src/main/java/freemarker/ext/beans/LegacyDefaultMemberAccessPolicy.java
@@ -93,6 +93,11 @@ public final class LegacyDefaultMemberAccessPolicy
implements MemberAccessPolicy
return CLASS_MEMBER_ACCESS_POLICY_INSTANCE;
}
+ @Override
+ public boolean isToStringAlwaysExposed() {
+ return true;
+ }
+
private static final BlacklistClassMemberAccessPolicy
CLASS_MEMBER_ACCESS_POLICY_INSTANCE
= new BlacklistClassMemberAccessPolicy();
private static class BlacklistClassMemberAccessPolicy implements
ClassMemberAccessPolicy {
diff --git a/src/main/java/freemarker/ext/beans/MemberAccessPolicy.java
b/src/main/java/freemarker/ext/beans/MemberAccessPolicy.java
index 400f1ce..2ca568d 100644
--- a/src/main/java/freemarker/ext/beans/MemberAccessPolicy.java
+++ b/src/main/java/freemarker/ext/beans/MemberAccessPolicy.java
@@ -70,4 +70,14 @@ public interface MemberAccessPolicy {
* The exact class of object from which members will be get in the
templates.
*/
ClassMemberAccessPolicy forClass(Class<?> contextClass);
+
+ /**
+ * If this returns {@code true}, we won't invoke the probably more
expensive lookup to figure out if
+ * {@link Object#toString()} (including its overridden variants) is
exposed for a given object. If this returns
+ * {@code false}, then no such optimization is made. This method was
introduced as {@link Object#toString()} is
+ * called frequently, as it's used whenever an object is converted to
string, like printed to the output, and it's
+ * not even a reflection-based call (we just call {@link
Object#toString()} in Java). So we try to avoid the
+ * overhead of a more generic method call.
+ */
+ boolean isToStringAlwaysExposed();
}
diff --git a/src/main/java/freemarker/ext/beans/StaticModel.java
b/src/main/java/freemarker/ext/beans/StaticModel.java
index cd1bf97..8e772aa 100644
--- a/src/main/java/freemarker/ext/beans/StaticModel.java
+++ b/src/main/java/freemarker/ext/beans/StaticModel.java
@@ -107,7 +107,7 @@ final class StaticModel implements TemplateHashModelEx {
}
ClassMemberAccessPolicy effClassMemberAccessPolicy =
-
wrapper.getClassIntrospector().getEffectiveClassMemberAccessPolicy(clazz);
+
wrapper.getClassIntrospector().getEffectiveMemberAccessPolicy().forClass(clazz);
Field[] fields = clazz.getFields();
for (Field field : fields) {
diff --git a/src/main/java/freemarker/ext/beans/StringModel.java
b/src/main/java/freemarker/ext/beans/StringModel.java
index 719e899..37a4923 100644
--- a/src/main/java/freemarker/ext/beans/StringModel.java
+++ b/src/main/java/freemarker/ext/beans/StringModel.java
@@ -39,6 +39,9 @@ implements TemplateScalarModel {
}
};
+ // Package visible for testing
+ static final String TO_STRING_NOT_EXPOSED = "[toString not exposed]";
+
/**
* Creates a new model that wraps the specified object with BeanModel +
scalar
* functionality.
@@ -56,7 +59,11 @@ implements TemplateScalarModel {
* Returns the result of calling {@link Object#toString()} on the wrapped
* object.
*/
+ @Override
public String getAsString() {
- return object.toString();
+ boolean exposeToString =
wrapper.getMemberAccessPolicy().isToStringAlwaysExposed()
+ || !wrapper.getClassIntrospector().get(object.getClass())
+
.containsKey(ClassIntrospector.TO_STRING_HIDDEN_FLAG_KEY);
+ return exposeToString ? object.toString() : TO_STRING_NOT_EXPOSED;
}
}
diff --git
a/src/main/java/freemarker/ext/beans/WhitelistMemberAccessPolicy.java
b/src/main/java/freemarker/ext/beans/WhitelistMemberAccessPolicy.java
index f024d37..e72f7bf 100644
--- a/src/main/java/freemarker/ext/beans/WhitelistMemberAccessPolicy.java
+++ b/src/main/java/freemarker/ext/beans/WhitelistMemberAccessPolicy.java
@@ -19,6 +19,7 @@
package freemarker.ext.beans;
+import java.lang.reflect.Method;
import java.util.Collection;
import freemarker.template.ObjectWrapper;
@@ -42,6 +43,17 @@ import freemarker.template.ObjectWrapper;
*/
public class WhitelistMemberAccessPolicy extends
MemberSelectorListMemberAccessPolicy {
+ private static final Method TO_STRING_METHOD;
+ static {
+ try {
+ TO_STRING_METHOD = Object.class.getMethod("toString");
+ } catch (NoSuchMethodException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ private final boolean toStringAlwaysExposed;
+
/**
* @param memberSelectors
* List of member selectors; see {@link
MemberSelectorListMemberAccessPolicy} class-level documentation for
@@ -49,6 +61,12 @@ public class WhitelistMemberAccessPolicy extends
MemberSelectorListMemberAccessP
*/
public WhitelistMemberAccessPolicy(Collection<? extends MemberSelector>
memberSelectors) {
super(memberSelectors, ListType.WHITELIST, TemplateAccessible.class);
+ toStringAlwaysExposed =
forClass(Object.class).isMethodExposed(TO_STRING_METHOD);
+ }
+
+ @Override
+ public boolean isToStringAlwaysExposed() {
+ return toStringAlwaysExposed;
}
}
diff --git
a/src/test/java/freemarker/ext/beans/DefaultMemberAccessPolicyTest.java
b/src/test/java/freemarker/ext/beans/DefaultMemberAccessPolicyTest.java
index 324abd1..4128151 100644
--- a/src/test/java/freemarker/ext/beans/DefaultMemberAccessPolicyTest.java
+++ b/src/test/java/freemarker/ext/beans/DefaultMemberAccessPolicyTest.java
@@ -81,6 +81,12 @@ public class DefaultMemberAccessPolicyTest {
}
@Test
+ public void testToString() throws NoSuchMethodException {
+ assertTrue(POLICY.isToStringAlwaysExposed());
+
assertTrue(POLICY.forClass(UserClass.class).isMethodExposed(Object.class.getMethod("toString")));
+ }
+
+ @Test
public void testWellKnownUnsafeMethodsAreBanned() throws
NoSuchMethodException {
{
ClassMemberAccessPolicy classPolicy = POLICY.forClass(Class.class);
diff --git
a/src/test/java/freemarker/ext/beans/DefaultObjectWrapperMemberAccessPolicyTest.java
b/src/test/java/freemarker/ext/beans/DefaultObjectWrapperMemberAccessPolicyTest.java
index 0938541..2c5ff54 100644
---
a/src/test/java/freemarker/ext/beans/DefaultObjectWrapperMemberAccessPolicyTest.java
+++
b/src/test/java/freemarker/ext/beans/DefaultObjectWrapperMemberAccessPolicyTest.java
@@ -48,6 +48,7 @@ import freemarker.template.TemplateMethodModelEx;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException;
import freemarker.template.TemplateNumberModel;
+import freemarker.template.TemplateScalarModel;
public class DefaultObjectWrapperMemberAccessPolicyTest {
@@ -247,6 +248,11 @@ public class DefaultObjectWrapperMemberAccessPolicyTest {
}
};
}
+
+ @Override
+ public boolean isToStringAlwaysExposed() {
+ return true;
+ }
});
DefaultObjectWrapper ow = owb.build();
@@ -286,6 +292,11 @@ public class DefaultObjectWrapperMemberAccessPolicyTest {
}
};
}
+
+ @Override
+ public boolean isToStringAlwaysExposed() {
+ return true;
+ }
});
DefaultObjectWrapper ow = owb.build();
@@ -315,6 +326,11 @@ public class DefaultObjectWrapperMemberAccessPolicyTest {
}
};
}
+
+ @Override
+ public boolean isToStringAlwaysExposed() {
+ return true;
+ }
});
DefaultObjectWrapper ow = owb.build();
@@ -342,6 +358,11 @@ public class DefaultObjectWrapperMemberAccessPolicyTest {
}
};
}
+
+ @Override
+ public boolean isToStringAlwaysExposed() {
+ return true;
+ }
});
DefaultObjectWrapper ow = owb.build();
@@ -386,6 +407,11 @@ public class DefaultObjectWrapperMemberAccessPolicyTest {
}
};
}
+
+ @Override
+ public boolean isToStringAlwaysExposed() {
+ return true;
+ }
});
DefaultObjectWrapper ow = owb.build();
@@ -429,6 +455,11 @@ public class DefaultObjectWrapperMemberAccessPolicyTest {
}
};
}
+
+ @Override
+ public boolean isToStringAlwaysExposed() {
+ return true;
+ }
});
DefaultObjectWrapper ow = owb.build();
@@ -478,6 +509,11 @@ public class DefaultObjectWrapperMemberAccessPolicyTest {
}
};
}
+
+ @Override
+ public boolean isToStringAlwaysExposed() {
+ return true;
+ }
});
DefaultObjectWrapper ow = owb.build();
TemplateHashModel statics = (TemplateHashModel)
ow.getStaticModels().get(Statics.class.getName());
@@ -530,6 +566,41 @@ public class DefaultObjectWrapperMemberAccessPolicyTest {
}
}
+ @Test
+ public void testToString1() throws TemplateException,
NoSuchMethodException, NoSuchFieldException,
+ ClassNotFoundException {
+ DefaultObjectWrapperBuilder owb = new
DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_30);
+ owb.setMemberAccessPolicy(
+ new WhitelistMemberAccessPolicy(
+
MemberSelectorListMemberAccessPolicy.MemberSelector.parse(
+
Collections.singleton(CExtended.class.getName() + ".toString()"),
+ false,
+
DefaultObjectWrapperMemberAccessPolicyTest.class.getClassLoader()
+ )
+ )
+ );
+ DefaultObjectWrapper ow = owb.build();
+
+ assertEquals(StringModel.TO_STRING_NOT_EXPOSED, ((TemplateScalarModel)
ow.wrap(new C())).getAsString());
+ assertEquals(CExtended.class.getSimpleName(), ((TemplateScalarModel)
ow.wrap(new CExtended())).getAsString());
+ }
+
+ @Test
+ public void testToString2() throws TemplateException {
+ for (MemberAccessPolicy policy :
+ new MemberAccessPolicy[] {
+
DefaultMemberAccessPolicy.getInstance(Configuration.VERSION_2_3_30),
+ LegacyDefaultMemberAccessPolicy.INSTANCE
+ }) {
+ DefaultObjectWrapperBuilder owb = new
DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_30);
+ owb.setMemberAccessPolicy(policy);
+ DefaultObjectWrapper ow = owb.build();
+
+ assertEquals(
+ C.class.getSimpleName(), ((TemplateScalarModel)
ow.wrap(new C())).getAsString());
+ }
+ }
+
private static Object getHashValue(ObjectWrapperAndUnwrapper ow,
TemplateHashModel objM, String key)
throws TemplateModelException {
return ow.unwrap(objM.get(key));
@@ -599,6 +670,11 @@ public class DefaultObjectWrapperMemberAccessPolicyTest {
}
public static void M1() { }
+
+ @Override
+ public String toString() {
+ return this.getClass().getSimpleName();
+ }
}
public static class CExtended extends C {
@@ -678,5 +754,10 @@ public class DefaultObjectWrapperMemberAccessPolicyTest {
}
};
}
+
+ @Override
+ public boolean isToStringAlwaysExposed() {
+ return false;
+ }
}
}
diff --git
a/src/test/java/freemarker/ext/beans/MemberSelectorListMemberAccessPolicyTest.java
b/src/test/java/freemarker/ext/beans/MemberSelectorListMemberAccessPolicyTest.java
index 2ba2458..861b5b8 100644
---
a/src/test/java/freemarker/ext/beans/MemberSelectorListMemberAccessPolicyTest.java
+++
b/src/test/java/freemarker/ext/beans/MemberSelectorListMemberAccessPolicyTest.java
@@ -314,7 +314,7 @@ public class MemberSelectorListMemberAccessPolicyTest {
}
@Test
- public void testBlacklistIgnoredAnnotation() throws NoSuchMethodException,
NoSuchFieldException {
+ public void testBlacklistIgnoresAnnotation() throws NoSuchMethodException,
NoSuchFieldException {
BlacklistMemberAccessPolicy policy = newBlacklistMemberAccessPolicy(
CAnnotationsTest1.class.getName() + ".m5()",
CAnnotationsTest1.class.getName() + ".f5",
@@ -328,6 +328,49 @@ public class MemberSelectorListMemberAccessPolicyTest {
}
@Test
+ public void testBlacklistAndToString() throws NoSuchMethodException {
+ {
+ BlacklistMemberAccessPolicy policy =
newBlacklistMemberAccessPolicy(
+ C1.class.getName() + ".m1()",
+ C1.class.getName() + ".m2()"
+ );
+ assertTrue(policy.isToStringAlwaysExposed());
+
assertTrue(policy.forClass(C1.class).isMethodExposed(Object.class.getMethod("toString")));
+ }
+ {
+ BlacklistMemberAccessPolicy policy =
newBlacklistMemberAccessPolicy(
+ C1.class.getName() + ".m1()",
+ C2.class.getName() + ".toString()",
+ C1.class.getName() + ".m2()"
+ );
+ assertFalse(policy.isToStringAlwaysExposed());
+
assertTrue(policy.forClass(C1.class).isMethodExposed(Object.class.getMethod("toString")));
+
assertFalse(policy.forClass(C2.class).isMethodExposed(Object.class.getMethod("toString")));
+
assertFalse(policy.forClass(C3.class).isMethodExposed(Object.class.getMethod("toString")));
+ }
+ }
+
+ @Test
+ public void testWhitelistAndToString() throws NoSuchMethodException {
+ {
+ WhitelistMemberAccessPolicy policy =
newWhitelistMemberAccessPolicy(
+ C2.class.getName() + ".toString()"
+ );
+ assertFalse(policy.isToStringAlwaysExposed());
+
assertFalse(policy.forClass(C1.class).isMethodExposed(Object.class.getMethod("toString")));
+
assertTrue(policy.forClass(C2.class).isMethodExposed(Object.class.getMethod("toString")));
+
assertTrue(policy.forClass(C3.class).isMethodExposed(Object.class.getMethod("toString")));
+ }
+ {
+ WhitelistMemberAccessPolicy policy =
newWhitelistMemberAccessPolicy(
+ Object.class.getName() + ".toString()"
+ );
+ assertTrue(policy.isToStringAlwaysExposed());
+
assertTrue(policy.forClass(C1.class).isMethodExposed(Object.class.getMethod("toString")));
+ }
+ }
+
+ @Test
public void memberSelectorParserIgnoresWhitespace() throws
NoSuchMethodException {
WhitelistMemberAccessPolicy policy = newWhitelistMemberAccessPolicy(
(CArrayArgs.class.getName() +
".m1(java.lang.String)").replace(".", "\n\t. "),