From e6c5561ca873595692b68a5fcbc6905bf4431206 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 | 13 ++++++++---- .../spel/support/ReflectionHelperTests.java | 20 +++++++++++++++++++ 2 files changed, 29 insertions(+), 4 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 621db0ec376b..853f4ff90244 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,18 @@ else if (canWrite(context, target, name)) { } /** - * 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 +301,7 @@ protected Method findGetterForProperty(String propertyName, Class clazz, bool } } // 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 42cdc2b40121..1b4941d5229b 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 @@ -319,6 +319,17 @@ public void testReflectivePropertyResolver() throws Exception { 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 +417,9 @@ static class Tester { 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 +429,12 @@ static class Tester { 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 {