Only consider "is" methods with boolean returns

Fix regression introduced in b25e91a5 where ReflectivePropertyAccessor
does not consider the return type for "is" getters.

Issue: SPR-11142
(cherry picked from commit 85b0bfff)
This commit is contained in:
Phillip Webb 2013-12-03 12:01:24 -08:00
parent 236981aaa9
commit dfed8afb26
2 changed files with 49 additions and 12 deletions

View File

@ -22,8 +22,11 @@ import java.lang.reflect.Member;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.springframework.core.MethodParameter; import org.springframework.core.MethodParameter;
@ -50,6 +53,17 @@ import org.springframework.util.StringUtils;
*/ */
public class ReflectivePropertyAccessor implements PropertyAccessor { public class ReflectivePropertyAccessor implements PropertyAccessor {
private static final Set<Class<?>> BOOLEAN_TYPES;
static {
Set<Class<?>> booleanTypes = new HashSet<Class<?>>();
booleanTypes.add(Boolean.class);
booleanTypes.add(Boolean.TYPE);
BOOLEAN_TYPES = Collections.unmodifiableSet(booleanTypes);
}
private static final Set<Class<?>> ANY_TYPES = Collections.emptySet();
private final Map<CacheKey, InvokerPair> readerCache = new ConcurrentHashMap<CacheKey, InvokerPair>(64); private final Map<CacheKey, InvokerPair> readerCache = new ConcurrentHashMap<CacheKey, InvokerPair>(64);
private final Map<CacheKey, Member> writerCache = new ConcurrentHashMap<CacheKey, Member>(64); private final Map<CacheKey, Member> writerCache = new ConcurrentHashMap<CacheKey, Member>(64);
@ -314,8 +328,13 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
* Find a getter method for the specified property. * Find a getter method for the specified property.
*/ */
protected Method findGetterForProperty(String propertyName, Class<?> clazz, boolean mustBeStatic) { protected Method findGetterForProperty(String propertyName, Class<?> clazz, boolean mustBeStatic) {
return findMethodForProperty(getPropertyMethodSuffixes(propertyName), Method method = findMethodForProperty(getPropertyMethodSuffixes(propertyName),
new String[] { "get", "is" }, clazz, mustBeStatic, 0); "get", clazz, mustBeStatic, 0, ANY_TYPES);
if (method == null) {
method = findMethodForProperty(getPropertyMethodSuffixes(propertyName),
"is", clazz, mustBeStatic, 0, BOOLEAN_TYPES);
}
return method;
} }
/** /**
@ -323,20 +342,19 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
*/ */
protected Method findSetterForProperty(String propertyName, Class<?> clazz, boolean mustBeStatic) { protected Method findSetterForProperty(String propertyName, Class<?> clazz, boolean mustBeStatic) {
return findMethodForProperty(getPropertyMethodSuffixes(propertyName), return findMethodForProperty(getPropertyMethodSuffixes(propertyName),
new String[] { "set" }, clazz, mustBeStatic, 1); "set", clazz, mustBeStatic, 1, ANY_TYPES);
} }
private Method findMethodForProperty(String[] methodSuffixes, String[] prefixes, Class<?> clazz, private Method findMethodForProperty(String[] methodSuffixes, String prefix, Class<?> clazz,
boolean mustBeStatic, int numberOfParams) { boolean mustBeStatic, int numberOfParams, Set<Class<?>> requiredReturnTypes) {
Method[] methods = getSortedClassMethods(clazz); Method[] methods = getSortedClassMethods(clazz);
for (String methodSuffix : methodSuffixes) { for (String methodSuffix : methodSuffixes) {
for (String prefix : prefixes) { for (Method method : methods) {
for (Method method : methods) { if (method.getName().equals(prefix + methodSuffix)
if (method.getName().equals(prefix + methodSuffix) && method.getParameterTypes().length == numberOfParams
&& method.getParameterTypes().length == numberOfParams && (!mustBeStatic || Modifier.isStatic(method.getModifiers()))
&& (!mustBeStatic || Modifier.isStatic(method.getModifiers()))) { && (requiredReturnTypes.isEmpty() || requiredReturnTypes.contains(method.getReturnType()))) {
return method; return method;
}
} }
} }
} }

View File

@ -1831,6 +1831,17 @@ public class SpelReproTests extends ExpressionTestCase {
equalTo((Object) "name")); equalTo((Object) "name"));
} }
@Test
public void SPR_11142() throws Exception {
SpelExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext();
SPR11142 rootObject = new SPR11142();
Expression expression = parser.parseExpression("something");
thrown.expect(SpelEvaluationException.class);
thrown.expectMessage("property 'something' cannot be found");
expression.getValue(context, rootObject);
}
private static enum ABC {A, B, C} private static enum ABC {A, B, C}
@ -1914,4 +1925,12 @@ public class SpelReproTests extends ExpressionTestCase {
} }
} }
static class SPR11142 {
public String isSomething() {
return "";
}
}
} }