MemberSelectorListMemberAccessPolicy related cleanup: Don't store the exception inside the MemberSelector
diff --git a/src/main/java/freemarker/ext/beans/DefaultMemberAccessPolicy.java b/src/main/java/freemarker/ext/beans/DefaultMemberAccessPolicy.java
index c27f662..71067c9 100644
--- a/src/main/java/freemarker/ext/beans/DefaultMemberAccessPolicy.java
+++ b/src/main/java/freemarker/ext/beans/DefaultMemberAccessPolicy.java
@@ -101,17 +101,24 @@
throw new IllegalStateException("Unhandled rule: " + rule);
}
} else {
- MemberSelector memberSelector =
- MemberSelector.parse(line, classLoader);
- Class<?> upperBoundType = memberSelector.getUpperBoundType();
- if (upperBoundType != null) {
- if (!whitelistRuleFinalClasses.contains(upperBoundType)
- && !whitelistRuleNonFinalClasses.contains(upperBoundType)
- && !typesWithBlacklistUnlistedRule.contains(upperBoundType)) {
- throw new IllegalStateException("Type without rule: " + upperBoundType.getName());
+ MemberSelector memberSelector;
+ try {
+ memberSelector = MemberSelector.parse(line, classLoader);
+ } catch (ClassNotFoundException | NoSuchMethodException | NoSuchFieldException e) {
+ // Can happen if we run on an older Java than the list was made for
+ memberSelector = null;
+ }
+ if (memberSelector != null) {
+ Class<?> upperBoundType = memberSelector.getUpperBoundType();
+ if (upperBoundType != null) {
+ if (!whitelistRuleFinalClasses.contains(upperBoundType)
+ && !whitelistRuleNonFinalClasses.contains(upperBoundType)
+ && !typesWithBlacklistUnlistedRule.contains(upperBoundType)) {
+ throw new IllegalStateException("Type without rule: " + upperBoundType.getName());
+ }
+ // We always do the same, as "blacklistUnlistedMembers" is also defined via a whitelist:
+ whitelistMemberSelectors.add(memberSelector);
}
- // We always do the same, as "blacklistUnlistedMembers" is also defined via a whitelist:
- whitelistMemberSelectors.add(memberSelector);
}
}
}
diff --git a/src/main/java/freemarker/ext/beans/MemberSelectorListMemberAccessPolicy.java b/src/main/java/freemarker/ext/beans/MemberSelectorListMemberAccessPolicy.java
index e0af091..a1eee12 100644
--- a/src/main/java/freemarker/ext/beans/MemberSelectorListMemberAccessPolicy.java
+++ b/src/main/java/freemarker/ext/beans/MemberSelectorListMemberAccessPolicy.java
@@ -28,7 +28,6 @@
import java.util.List;
import java.util.StringTokenizer;
-import freemarker.log.Logger;
import freemarker.template.utility.ClassUtil;
import freemarker.template.utility.NullArgumentException;
@@ -68,8 +67,6 @@
* @since 2.3.30
*/
public abstract class MemberSelectorListMemberAccessPolicy implements MemberAccessPolicy {
- private static final Logger LOG = Logger.getLogger("freemarker.beans");
-
enum ListType {
/** Only matched members will be exposed. */
WHITELIST,
@@ -86,7 +83,7 @@
/**
* A condition that matches some type members. See {@link MemberSelectorListMemberAccessPolicy} documentation for more.
* Exactly one of these will be non-{@code null}:
- * {@link #getMethod()}, {@link #getConstructor()}, {@link #getField()}, {@link #getException()}.
+ * {@link #getMethod()}, {@link #getConstructor()}, {@link #getField()}.
*
* @since 2.3.30
*/
@@ -95,8 +92,6 @@
private final Method method;
private final Constructor<?> constructor;
private final Field field;
- private final Exception exception;
- private final String exceptionMemberSelectorString;
/**
* Use if you want to match methods similar to the specified one, in types that are {@code instanceof} of
@@ -109,8 +104,6 @@
this.method = method;
this.constructor = null;
this.field = null;
- this.exception = null;
- this.exceptionMemberSelectorString = null;
}
/**
@@ -124,8 +117,6 @@
this.method = null;
this.constructor = constructor;
this.field = null;
- this.exception = null;
- this.exceptionMemberSelectorString = null;
}
/**
@@ -139,32 +130,10 @@
this.method = null;
this.constructor = null;
this.field = field;
- this.exception = null;
- this.exceptionMemberSelectorString = null;
}
/**
- * Used to store the result of a parsing that's failed for a reason that we can skip on runtime (typically,
- * when a missing class or member was referred).
- *
- * @param upperBoundType {@code null} if resolving the upper bound type itself failed.
- * @param exception Not {@code null}
- * @param exceptionMemberSelectorString Not {@code null}; the selector whose resolution has failed, used in
- * the log message.
- */
- public MemberSelector(Class<?> upperBoundType, Exception exception, String exceptionMemberSelectorString) {
- NullArgumentException.check("exception", exception);
- NullArgumentException.check("exceptionMemberSelectorString", exceptionMemberSelectorString);
- this.upperBoundType = upperBoundType;
- this.method = null;
- this.constructor = null;
- this.field = null;
- this.exception = exception;
- this.exceptionMemberSelectorString = exceptionMemberSelectorString;
- }
-
- /**
- * Maybe {@code null} if {@link #getException()} is non-{@code null}.
+ * Not {@code null}.
*/
public Class<?> getUpperBoundType() {
return upperBoundType;
@@ -172,7 +141,7 @@
/**
* Maybe {@code null};
- * set if the selector matches methods similar to the returned one, and there was no exception.
+ * set if the selector matches methods similar to the returned one.
*/
public Method getMethod() {
return method;
@@ -180,7 +149,7 @@
/**
* Maybe {@code null};
- * set if the selector matches constructors similar to the returned one, and there was no exception.
+ * set if the selector matches constructors similar to the returned one.
*/
public Constructor<?> getConstructor() {
return constructor;
@@ -188,27 +157,13 @@
/**
* Maybe {@code null};
- * set if the selector matches fields similar to the returned one, and there was no exception.
+ * set if the selector matches fields similar to the returned one.
*/
public Field getField() {
return field;
}
/**
- * Maybe {@code null}
- */
- public Exception getException() {
- return exception;
- }
-
- /**
- * Maybe {@code null}
- */
- public String getExceptionMemberSelectorString() {
- return exceptionMemberSelectorString;
- }
-
- /**
* Parses a member selector that was specified with a string.
*
* @param classLoader
@@ -226,9 +181,12 @@
* {@code []}. In the member name, like {@code com.example.MyClass.myMember}, the class refers to the so
* called "upper bound class". Regarding that and inheritance rules see the class level documentation.
*
- * @return The {@link MemberSelector}, which might has non-{@code null} {@link MemberSelector#exception}.
+ * @throws ClassNotFoundException If a type referred in the member selector can't be found.
+ * @throws NoSuchMethodException If the method or constructor referred in the member selector can't be found.
+ * @throws NoSuchFieldException If the field referred in the member selector can't be found.
*/
- public static MemberSelector parse(String memberSelectorString, ClassLoader classLoader) {
+ public static MemberSelector parse(String memberSelectorString, ClassLoader classLoader) throws
+ ClassNotFoundException, NoSuchMethodException, NoSuchFieldException {
if (memberSelectorString.contains("<") || memberSelectorString.contains(">")
|| memberSelectorString.contains("...") || memberSelectorString.contains(";")) {
throw new IllegalArgumentException(
@@ -256,11 +214,7 @@
throw new IllegalArgumentException("Malformed whitelist entry (malformed upper bound class name): "
+ memberSelectorString);
}
- try {
- upperBoundClass = classLoader.loadClass(upperBoundClassStr);
- } catch (ClassNotFoundException e) {
- return new MemberSelector(null, e, cleanedStr);
- }
+ upperBoundClass = classLoader.loadClass(upperBoundClassStr);
String memberName = cleanedStr.substring(postClassDotIdx + 1, postMemberNameIdx);
if (!isWellFormedJavaIdentifier(memberName)) {
@@ -293,33 +247,15 @@
throw new IllegalArgumentException(
"Malformed whitelist entry (malformed argument class name): " + memberSelectorString);
}
- try {
- argClass = classLoader.loadClass(argClassName);
- } catch (ClassNotFoundException e) {
- return new MemberSelector(upperBoundClass, e, cleanedStr);
- } catch (SecurityException e) {
- return new MemberSelector(upperBoundClass, e, cleanedStr);
- }
+ argClass = classLoader.loadClass(argClassName);
}
argTypes[i] = ClassUtil.getArrayClass(argClass, arrayDimensions);
}
- try {
- return memberName.equals(upperBoundClass.getSimpleName())
- ? new MemberSelector(upperBoundClass, upperBoundClass.getConstructor(argTypes))
- : new MemberSelector(upperBoundClass, upperBoundClass.getMethod(memberName, argTypes));
- } catch (NoSuchMethodException e) {
- return new MemberSelector(upperBoundClass, e, cleanedStr);
- } catch (SecurityException e) {
- return new MemberSelector(upperBoundClass, e, cleanedStr);
- }
+ return memberName.equals(upperBoundClass.getSimpleName())
+ ? new MemberSelector(upperBoundClass, upperBoundClass.getConstructor(argTypes))
+ : new MemberSelector(upperBoundClass, upperBoundClass.getMethod(memberName, argTypes));
} else {
- try {
- return new MemberSelector(upperBoundClass, upperBoundClass.getField(memberName));
- } catch (NoSuchFieldException e) {
- return new MemberSelector(upperBoundClass, e, cleanedStr);
- } catch (SecurityException e) {
- return new MemberSelector(upperBoundClass, e, cleanedStr);
- }
+ return new MemberSelector(upperBoundClass, upperBoundClass.getField(memberName));
}
}
@@ -327,13 +263,24 @@
* Convenience method to parse all member selectors in the collection (see {@link #parse(String, ClassLoader)}),
* while also filtering out blank and comment lines; see {@link #parse(String, ClassLoader)},
* and {@link #isIgnoredLine(String)}.
+ *
+ * @param ignoreMissingClassOrMember If {@code true}, members selectors that throw exceptions because the
+ * referred type or member can't be found will be silently ignored. If {@code true}, same exceptions
+ * will be just thrown by this method.
*/
- public static List<MemberSelector> parse(Collection<String> memberSelectors,
- ClassLoader classLoader) {
+ public static List<MemberSelector> parse(
+ Collection<String> memberSelectors, boolean ignoreMissingClassOrMember, ClassLoader classLoader)
+ throws ClassNotFoundException, NoSuchMethodException, NoSuchFieldException {
List<MemberSelector> parsedMemberSelectors = new ArrayList<MemberSelector>(memberSelectors.size());
for (String memberSelector : memberSelectors) {
if (!isIgnoredLine(memberSelector)) {
- parsedMemberSelectors.add(parse(memberSelector, classLoader));
+ try {
+ parsedMemberSelectors.add(parse(memberSelector, classLoader));
+ } catch (ClassNotFoundException | NoSuchFieldException | NoSuchMethodException e) {
+ if (!ignoreMissingClassOrMember) {
+ throw e;
+ }
+ }
}
}
return parsedMemberSelectors;
@@ -369,12 +316,7 @@
fieldMatcher = new FieldMatcher();
for (MemberSelector memberSelector : memberSelectors) {
Class<?> upperBoundClass = memberSelector.upperBoundType;
- if (memberSelector.exception != null) {
- if (LOG.isDebugEnabled()) {
- LOG.debug("Member selector ignored due to error: " + memberSelector.getExceptionMemberSelectorString(),
- memberSelector.exception);
- }
- } else if (memberSelector.constructor != null) {
+ if (memberSelector.constructor != null) {
constructorMatcher.addMatching(upperBoundClass, memberSelector.constructor);
} else if (memberSelector.method != null) {
methodMatcher.addMatching(upperBoundClass, memberSelector.method);
diff --git a/src/test/java/freemarker/ext/beans/MemberSelectorListAccessPolicyTest.java b/src/test/java/freemarker/ext/beans/MemberSelectorListMemberAccessPolicyTest.java
similarity index 96%
rename from src/test/java/freemarker/ext/beans/MemberSelectorListAccessPolicyTest.java
rename to src/test/java/freemarker/ext/beans/MemberSelectorListMemberAccessPolicyTest.java
index 1250c2a..2ba2458 100644
--- a/src/test/java/freemarker/ext/beans/MemberSelectorListAccessPolicyTest.java
+++ b/src/test/java/freemarker/ext/beans/MemberSelectorListMemberAccessPolicyTest.java
@@ -27,7 +27,7 @@
import org.junit.Test;
-public class MemberSelectorListAccessPolicyTest {
+public class MemberSelectorListMemberAccessPolicyTest {
@Test
public void testEmpty() throws NoSuchMethodException, NoSuchFieldException {
@@ -427,17 +427,25 @@
}
private static WhitelistMemberAccessPolicy newWhitelistMemberAccessPolicy(String... memberSelectors) {
- return new WhitelistMemberAccessPolicy(
- MemberSelectorListMemberAccessPolicy.MemberSelector.parse(
- Arrays.asList(memberSelectors),
- MemberSelectorListAccessPolicyTest.class.getClassLoader()));
+ try {
+ return new WhitelistMemberAccessPolicy(
+ MemberSelectorListMemberAccessPolicy.MemberSelector.parse(
+ Arrays.asList(memberSelectors), false,
+ MemberSelectorListMemberAccessPolicyTest.class.getClassLoader()));
+ } catch (ClassNotFoundException | NoSuchMethodException | NoSuchFieldException e) {
+ throw new RuntimeException(e);
+ }
}
private static BlacklistMemberAccessPolicy newBlacklistMemberAccessPolicy(String... memberSelectors) {
- return new BlacklistMemberAccessPolicy(
- MemberSelectorListMemberAccessPolicy.MemberSelector.parse(
- Arrays.asList(memberSelectors),
- MemberSelectorListAccessPolicyTest.class.getClassLoader()));
+ try {
+ return new BlacklistMemberAccessPolicy(
+ MemberSelectorListMemberAccessPolicy.MemberSelector.parse(
+ Arrays.asList(memberSelectors), false,
+ MemberSelectorListMemberAccessPolicyTest.class.getClassLoader()));
+ } catch (ClassNotFoundException | NoSuchMethodException | NoSuchFieldException e) {
+ throw new RuntimeException(e);
+ }
}
public static class C1 {
diff --git a/src/test/java/freemarker/template/ConfigurationTest.java b/src/test/java/freemarker/template/ConfigurationTest.java
index 4b77eef..3ab21cc 100644
--- a/src/test/java/freemarker/template/ConfigurationTest.java
+++ b/src/test/java/freemarker/template/ConfigurationTest.java
@@ -1901,12 +1901,19 @@
assertFalse(cfg.getFallbackOnNullLoopVariable());
}
- public static final MemberAccessPolicy CONFIG_TEST_MEMBER_ACCESS_POLICY =
- new WhitelistMemberAccessPolicy(MemberSelectorListMemberAccessPolicy.MemberSelector.parse(
+ public static final MemberAccessPolicy CONFIG_TEST_MEMBER_ACCESS_POLICY;
+ static {
+ try {
+ CONFIG_TEST_MEMBER_ACCESS_POLICY = new WhitelistMemberAccessPolicy(MemberSelectorListMemberAccessPolicy.MemberSelector.parse(
ImmutableList.<String>of(
File.class.getName() + ".getName()",
File.class.getName() + ".isFile()"),
+ false,
ConfigurationTest.class.getClassLoader()));
+ } catch (ClassNotFoundException | NoSuchMethodException | NoSuchFieldException e) {
+ throw new RuntimeException(e);
+ }
+ }
@Test
public void testMemberAccessPolicySetting() throws TemplateException {
diff --git a/src/test/java/freemarker/template/DefaultObjectWrapperTest.java b/src/test/java/freemarker/template/DefaultObjectWrapperTest.java
index 12f4954..0719f00 100644
--- a/src/test/java/freemarker/template/DefaultObjectWrapperTest.java
+++ b/src/test/java/freemarker/template/DefaultObjectWrapperTest.java
@@ -328,7 +328,7 @@
WhitelistMemberAccessPolicy memberAccessPolicy =
new WhitelistMemberAccessPolicy(
WhitelistMemberAccessPolicy.MemberSelector.parse(
- Arrays.asList(SomeBean.class.getName() + ".getX()"),
+ Arrays.asList(SomeBean.class.getName() + ".getX()"), false,
DefaultObjectWrapperTest.class.getClassLoader()));
builder.setMemberAccessPolicy(memberAccessPolicy);
DefaultObjectWrapper bw = builder.build();