Skip to content

Commit 1f28bdf

Browse files
sslaviccbeams
authored andcommitted
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
1 parent 2503b7e commit 1f28bdf

File tree

2 files changed

+30
-5
lines changed

2 files changed

+30
-5
lines changed

spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -282,21 +282,27 @@ else if (canWrite(context, target, name)) {
282282
}
283283

284284
/**
285-
* Find a getter method for the specified property. A getter is defined as a method whose name start with the prefix
286-
* 'get' and the rest of the name is the same as the property name (with the first character uppercased).
285+
* Find a getter method for the specified property.
287286
*/
288287
protected Method findGetterForProperty(String propertyName, Class<?> clazz, boolean mustBeStatic) {
289288
Method[] ms = clazz.getMethods();
289+
String propertyWriteMethodSuffix;
290+
if (propertyName.length() > 1 && Character.isUpperCase(propertyName.charAt(1))) {
291+
propertyWriteMethodSuffix = propertyName;
292+
}
293+
else {
294+
propertyWriteMethodSuffix = StringUtils.capitalize(propertyName);
295+
}
290296
// Try "get*" method...
291-
String getterName = "get" + StringUtils.capitalize(propertyName);
297+
String getterName = "get" + propertyWriteMethodSuffix;
292298
for (Method method : ms) {
293299
if (method.getName().equals(getterName) && method.getParameterTypes().length == 0 &&
294300
(!mustBeStatic || Modifier.isStatic(method.getModifiers()))) {
295301
return method;
296302
}
297303
}
298304
// Try "is*" method...
299-
getterName = "is" + StringUtils.capitalize(propertyName);
305+
getterName = "is" + propertyWriteMethodSuffix;
300306
for (Method method : ms) {
301307
if (method.getName().equals(getterName) && method.getParameterTypes().length == 0 &&
302308
boolean.class.equals(method.getReturnType()) &&

spring-expression/src/test/java/org/springframework/expression/spel/support/ReflectionHelperTests.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,17 @@ public void testReflectivePropertyResolver() throws Exception {
318318
// Assert.assertEquals(0,rpr.read(ctx,t,"field3").getValue());
319319
Assert.assertEquals(false,rpr.read(ctx,t,"property4").getValue());
320320
Assert.assertTrue(rpr.canRead(ctx,t,"property4"));
321-
321+
322+
// repro SPR-9123, ReflectivePropertyAccessor JavaBean property names compliance tests
323+
Assert.assertEquals("iD",rpr.read(ctx,t,"iD").getValue());
324+
Assert.assertTrue(rpr.canRead(ctx,t,"iD"));
325+
Assert.assertEquals("id",rpr.read(ctx,t,"id").getValue());
326+
Assert.assertTrue(rpr.canRead(ctx,t,"id"));
327+
Assert.assertEquals("ID",rpr.read(ctx,t,"ID").getValue());
328+
Assert.assertTrue(rpr.canRead(ctx,t,"ID"));
329+
// note: "Id" is not a valid JavaBean name, nevertheless it is treated as "id"
330+
Assert.assertEquals("id",rpr.read(ctx,t,"Id").getValue());
331+
Assert.assertTrue(rpr.canRead(ctx,t,"Id"));
322332
}
323333

324334
@Test
@@ -406,6 +416,9 @@ static class Tester {
406416
String property2;
407417
String property3 = "doodoo";
408418
boolean property4 = false;
419+
String iD = "iD";
420+
String id = "id";
421+
String ID = "ID";
409422

410423
public String getProperty() { return property; }
411424
public void setProperty(String value) { property = value; }
@@ -415,6 +428,12 @@ static class Tester {
415428
public String getProperty3() { return property3; }
416429

417430
public boolean isProperty4() { return property4; }
431+
432+
public String getiD() { return iD; }
433+
434+
public String getId() { return id; }
435+
436+
public String getID() { return ID; }
418437
}
419438

420439
static class Super {

0 commit comments

Comments
 (0)