From 1f28bdfbfa7f6f7025dac18bd5cdf4fdefb32950 Mon Sep 17 00:00:00 2001 From: Stevo Slavic Date: Sat, 3 Mar 2012 10:45:44 +0100 Subject: [PATCH] Fix SpEL JavaBean compliance Before this fix ReflectivePropertyAccessor was not able to find write method for valid property name that has first character in lower case and second character in upper case. Write method lookup would always convert first character of property name to upper case which is not compliant with JavaBean specification. As consequence this caused an unwanted behavior in SpEL when obtaining values of expressions that reference such JavaBean properties. As of this change, write method lookup skips conversion of property name first character to upper case when property name is longer than one character and second character is in upper case. This also fixes mentioned bug in SpEL value resolution. Issue: SPR-9123 --- .../support/ReflectivePropertyAccessor.java | 14 +++++++++---- .../spel/support/ReflectionHelperTests.java | 21 ++++++++++++++++++- 2 files changed, 30 insertions(+), 5 deletions(-) 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 621db0ec37..3409bd47f9 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 @@ -282,13 +282,19 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { } /** - * Find a getter method for the specified property. A getter is defined as a method whose name start with the prefix - * 'get' and the rest of the name is the same as the property name (with the first character uppercased). + * Find a getter method for the specified property. */ protected Method findGetterForProperty(String propertyName, Class clazz, boolean mustBeStatic) { Method[] ms = clazz.getMethods(); + String propertyWriteMethodSuffix; + if (propertyName.length() > 1 && Character.isUpperCase(propertyName.charAt(1))) { + propertyWriteMethodSuffix = propertyName; + } + else { + propertyWriteMethodSuffix = StringUtils.capitalize(propertyName); + } // Try "get*" method... - String getterName = "get" + StringUtils.capitalize(propertyName); + String getterName = "get" + propertyWriteMethodSuffix; for (Method method : ms) { if (method.getName().equals(getterName) && method.getParameterTypes().length == 0 && (!mustBeStatic || Modifier.isStatic(method.getModifiers()))) { @@ -296,7 +302,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { } } // Try "is*" method... - getterName = "is" + StringUtils.capitalize(propertyName); + getterName = "is" + propertyWriteMethodSuffix; for (Method method : ms) { if (method.getName().equals(getterName) && method.getParameterTypes().length == 0 && boolean.class.equals(method.getReturnType()) && 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 42cdc2b401..2bc87f90fb 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 @@ -318,7 +318,17 @@ public class ReflectionHelperTests extends ExpressionTestCase { // Assert.assertEquals(0,rpr.read(ctx,t,"field3").getValue()); Assert.assertEquals(false,rpr.read(ctx,t,"property4").getValue()); Assert.assertTrue(rpr.canRead(ctx,t,"property4")); - + + // repro SPR-9123, ReflectivePropertyAccessor JavaBean property names compliance tests + Assert.assertEquals("iD",rpr.read(ctx,t,"iD").getValue()); + Assert.assertTrue(rpr.canRead(ctx,t,"iD")); + Assert.assertEquals("id",rpr.read(ctx,t,"id").getValue()); + Assert.assertTrue(rpr.canRead(ctx,t,"id")); + Assert.assertEquals("ID",rpr.read(ctx,t,"ID").getValue()); + Assert.assertTrue(rpr.canRead(ctx,t,"ID")); + // note: "Id" is not a valid JavaBean name, nevertheless it is treated as "id" + Assert.assertEquals("id",rpr.read(ctx,t,"Id").getValue()); + Assert.assertTrue(rpr.canRead(ctx,t,"Id")); } @Test @@ -406,6 +416,9 @@ public class ReflectionHelperTests extends ExpressionTestCase { String property2; String property3 = "doodoo"; boolean property4 = false; + String iD = "iD"; + String id = "id"; + String ID = "ID"; public String getProperty() { return property; } public void setProperty(String value) { property = value; } @@ -415,6 +428,12 @@ public class ReflectionHelperTests extends ExpressionTestCase { public String getProperty3() { return property3; } public boolean isProperty4() { return property4; } + + public String getiD() { return iD; } + + public String getId() { return id; } + + public String getID() { return ID; } } static class Super {