diff --git a/spring-beans/src/main/java/org/springframework/beans/AbstractNestablePropertyAccessor.java b/spring-beans/src/main/java/org/springframework/beans/AbstractNestablePropertyAccessor.java index 9790cf7978..54cd9bd0b6 100644 --- a/spring-beans/src/main/java/org/springframework/beans/AbstractNestablePropertyAccessor.java +++ b/spring-beans/src/main/java/org/springframework/beans/AbstractNestablePropertyAccessor.java @@ -933,7 +933,7 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA int keyStart = propertyName.indexOf(PROPERTY_KEY_PREFIX, searchIndex); searchIndex = -1; if (keyStart != -1) { - int keyEnd = propertyName.indexOf(PROPERTY_KEY_SUFFIX, keyStart + PROPERTY_KEY_PREFIX.length()); + int keyEnd = getPropertyNameKeyEnd(propertyName, keyStart + PROPERTY_KEY_PREFIX.length()); if (keyEnd != -1) { if (actualName == null) { actualName = propertyName.substring(0, keyStart); @@ -958,6 +958,29 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA return tokens; } + private static int getPropertyNameKeyEnd(String propertyName, int startIndex) { + int unclosedPrefixes = 0; + int length = propertyName.length(); + for (int i = startIndex; i < length; i++) { + switch (propertyName.charAt(i)) { + case PropertyAccessor.PROPERTY_KEY_PREFIX_CHAR: + // The property name contains opening prefix(es) + unclosedPrefixes++; + break; + case PropertyAccessor.PROPERTY_KEY_SUFFIX_CHAR: + if (unclosedPrefixes == 0) { + // No unclosed prefix(es) in the property name (left), this is the suffix we are looking for + return i; + } else { + // This suffix does not close the initial prefix, but one that occurred within the property name + unclosedPrefixes--; + } + break; + } + } + return -1; + } + @Override public String toString() { StringBuilder sb = new StringBuilder(getClass().getName()); diff --git a/spring-beans/src/test/java/org/springframework/beans/AbstractPropertyAccessorTests.java b/spring-beans/src/test/java/org/springframework/beans/AbstractPropertyAccessorTests.java index fb3b89e657..97667cb599 100644 --- a/spring-beans/src/test/java/org/springframework/beans/AbstractPropertyAccessorTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/AbstractPropertyAccessorTests.java @@ -1599,6 +1599,7 @@ public abstract class AbstractPropertyAccessorTests { TestBean tb7 = ((TestBean) target.getSet().toArray()[1]); TestBean tb4 = ((TestBean) target.getMap().get("key1")); TestBean tb5 = ((TestBean) target.getMap().get("key.3")); + TestBean tb8 = ((TestBean) target.getMap().get("key5[foo]")); assertEquals("name0", tb0.getName()); assertEquals("name1", tb1.getName()); assertEquals("name2", tb2.getName()); @@ -1607,6 +1608,7 @@ public abstract class AbstractPropertyAccessorTests { assertEquals("name7", tb7.getName()); assertEquals("name4", tb4.getName()); assertEquals("name5", tb5.getName()); + assertEquals("name8", tb8.getName()); assertEquals("name0", accessor.getPropertyValue("array[0].name")); assertEquals("name1", accessor.getPropertyValue("array[1].name")); assertEquals("name2", accessor.getPropertyValue("list[0].name")); @@ -1619,6 +1621,9 @@ public abstract class AbstractPropertyAccessorTests { assertEquals("name5", accessor.getPropertyValue("map[\"key.3\"].name")); assertEquals("nameX", accessor.getPropertyValue("map[key4][0].name")); assertEquals("nameY", accessor.getPropertyValue("map[key4][1].name")); + assertEquals("name8", accessor.getPropertyValue("map[key5[foo]].name")); + assertEquals("name8", accessor.getPropertyValue("map['key5[foo]'].name")); + assertEquals("name8", accessor.getPropertyValue("map[\"key5[foo]\"].name")); MutablePropertyValues pvs = new MutablePropertyValues(); pvs.add("array[0].name", "name5"); @@ -1631,6 +1636,7 @@ public abstract class AbstractPropertyAccessorTests { pvs.add("map['key.3'].name", "name0"); pvs.add("map[key4][0].name", "nameA"); pvs.add("map[key4][1].name", "nameB"); + pvs.add("map[key5[foo]].name", "name10"); accessor.setPropertyValues(pvs); assertEquals("name5", tb0.getName()); assertEquals("name4", tb1.getName()); @@ -1648,6 +1654,7 @@ public abstract class AbstractPropertyAccessorTests { assertEquals("name0", accessor.getPropertyValue("map['key.3'].name")); assertEquals("nameA", accessor.getPropertyValue("map[key4][0].name")); assertEquals("nameB", accessor.getPropertyValue("map[key4][1].name")); + assertEquals("name10", accessor.getPropertyValue("map[key5[foo]].name")); } @Test diff --git a/spring-beans/src/test/java/org/springframework/tests/sample/beans/IndexedTestBean.java b/spring-beans/src/test/java/org/springframework/tests/sample/beans/IndexedTestBean.java index ae7f8d7764..b71c53471e 100644 --- a/spring-beans/src/test/java/org/springframework/tests/sample/beans/IndexedTestBean.java +++ b/spring-beans/src/test/java/org/springframework/tests/sample/beans/IndexedTestBean.java @@ -66,6 +66,7 @@ public class IndexedTestBean { TestBean tb5 = new TestBean("name5", 0); TestBean tb6 = new TestBean("name6", 0); TestBean tb7 = new TestBean("name7", 0); + TestBean tb8 = new TestBean("name8", 0); TestBean tbX = new TestBean("nameX", 0); TestBean tbY = new TestBean("nameY", 0); this.array = new TestBean[] {tb0, tb1}; @@ -83,6 +84,7 @@ public class IndexedTestBean { list.add(tbX); list.add(tbY); this.map.put("key4", list); + this.map.put("key5[foo]", tb8); }