diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java index 021898d849b..c1055e5fddc 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java @@ -314,42 +314,34 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { * Find a getter method for the specified property. */ protected Method findGetterForProperty(String propertyName, Class clazz, boolean mustBeStatic) { - Method[] ms = getSortedClassMethods(clazz); - String propertyMethodSuffix = getPropertyMethodSuffix(propertyName); - - // Try "get*" method... - String getterName = "get" + propertyMethodSuffix; - for (Method method : ms) { - if (method.getName().equals(getterName) && method.getParameterTypes().length == 0 && - (!mustBeStatic || Modifier.isStatic(method.getModifiers()))) { - return method; - } - } - // Try "is*" method... - getterName = "is" + propertyMethodSuffix; - for (Method method : ms) { - if (method.getName().equals(getterName) && method.getParameterTypes().length == 0 && - (boolean.class.equals(method.getReturnType()) || Boolean.class.equals(method.getReturnType())) && - (!mustBeStatic || Modifier.isStatic(method.getModifiers()))) { - return method; - } - } - return null; + return findMethodForProperty(getPropertyMethodSuffixes(propertyName), + new String[] { "get", "is" }, clazz, mustBeStatic, 0); } /** * Find a setter method for the specified property. */ protected Method findSetterForProperty(String propertyName, Class clazz, boolean mustBeStatic) { + return findMethodForProperty(getPropertyMethodSuffixes(propertyName), + new String[] { "set" }, clazz, mustBeStatic, 1); + } + + private Method findMethodForProperty(String[] methodSuffixes, String[] prefixes, Class clazz, + boolean mustBeStatic, int numberOfParams) { Method[] methods = getSortedClassMethods(clazz); - String setterName = "set" + getPropertyMethodSuffix(propertyName); - for (Method method : methods) { - if (method.getName().equals(setterName) && method.getParameterTypes().length == 1 && - (!mustBeStatic || Modifier.isStatic(method.getModifiers()))) { - return method; + for (String methodSuffix : methodSuffixes) { + for (String prefix : prefixes) { + for (Method method : methods) { + if (method.getName().equals(prefix + methodSuffix) + && method.getParameterTypes().length == numberOfParams + && (!mustBeStatic || Modifier.isStatic(method.getModifiers()))) { + return method; + } + } } } return null; + } /** @@ -365,13 +357,29 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { return methods; } + /** + * Return the method suffixes for a given property name. The default implementation + * uses JavaBean conventions with additional support for properties of the form 'xY' + * where the method 'getXY()' is used in preference to the JavaBean convention of + * 'getxY()'. + */ + protected String[] getPropertyMethodSuffixes(String propertyName) { + String suffix = getPropertyMethodSuffix(propertyName); + if (suffix.length() > 0 && Character.isUpperCase(suffix.charAt(0))) { + return new String[] { suffix }; + } + return new String[] { suffix, StringUtils.capitalize(suffix) }; + } + + /** + * Return the method suffix for a given property name. The default implementation + * uses JavaBean conventions. + */ protected String getPropertyMethodSuffix(String propertyName) { if (propertyName.length() > 1 && Character.isUpperCase(propertyName.charAt(1))) { return propertyName; } - else { - return StringUtils.capitalize(propertyName); - } + return StringUtils.capitalize(propertyName); } /** diff --git a/spring-expression/src/test/java/org/springframework/expression/spel/support/ReflectionHelperTests.java b/spring-expression/src/test/java/org/springframework/expression/spel/support/ReflectionHelperTests.java index c31a94a71b4..68911b9bcef 100644 --- a/spring-expression/src/test/java/org/springframework/expression/spel/support/ReflectionHelperTests.java +++ b/spring-expression/src/test/java/org/springframework/expression/spel/support/ReflectionHelperTests.java @@ -335,6 +335,12 @@ public class ReflectionHelperTests extends ExpressionTestCase { assertEquals("id",rpr.read(ctx,t,"Id").getValue()); assertTrue(rpr.canRead(ctx,t,"Id")); + // repro SPR-10994 + assertEquals("xyZ",rpr.read(ctx,t,"xyZ").getValue()); + assertTrue(rpr.canRead(ctx,t,"xyZ")); + assertEquals("xY",rpr.read(ctx,t,"xY").getValue()); + assertTrue(rpr.canRead(ctx,t,"xY")); + // SPR-10122, ReflectivePropertyAccessor JavaBean property names compliance tests - setters rpr.write(ctx, t, "pEBS","Test String"); assertEquals("Test String",rpr.read(ctx,t,"pEBS").getValue()); @@ -429,6 +435,8 @@ public class ReflectionHelperTests extends ExpressionTestCase { String id = "id"; String ID = "ID"; String pEBS = "pEBS"; + String xY = "xY"; + String xyZ = "xyZ"; public String getProperty() { return property; } public void setProperty(String value) { property = value; } @@ -445,6 +453,10 @@ public class ReflectionHelperTests extends ExpressionTestCase { public String getID() { return ID; } + public String getXY() { return xY; } + + public String getXyZ() { return xyZ; } + public String getpEBS() { return pEBS; }