Re-write of path parsing pieces of RelaxedDataBinder

Keys with explicit indexes (e.g. foo[bar]) were handled only
partially before this change and in quite a crude way. The main
new feature (or fixed bug if you prefer) is that map keys with
periods were not identified correctly, so foo[bar.spam] came out
wrong. By scanning the key for indexes "[]" first, we can split
the logic better to make sure that all keys can be explicitly
indexed if desired. I believe this would work in YAML as well
but it definitely works for properties file inputs.

Fixes gh-2387 (I believe)
pull/2809/head
Dave Syer 10 years ago
parent 44a708ea5c
commit ff637d3aaa

@ -451,11 +451,26 @@ public class RelaxedDataBinder extends DataBinder {
private List<PathNode> splitPath(String path) { private List<PathNode> splitPath(String path) {
List<PathNode> nodes = new ArrayList<PathNode>(); List<PathNode> nodes = new ArrayList<PathNode>();
for (String name : StringUtils.delimitedListToStringArray(path, ".")) { String current = extractIndexedPaths(path, nodes);
for (String sub : StringUtils.delimitedListToStringArray(name, "[")) { for (String name : StringUtils.delimitedListToStringArray(current, ".")) {
if (StringUtils.hasText(sub)) { if (StringUtils.hasText(name)) {
if (sub.endsWith("]")) { nodes.add(new PropertyNode(name));
sub = sub.substring(0, sub.length() - 1); }
}
return nodes;
}
private String extractIndexedPaths(String path, List<PathNode> nodes) {
int begin = 0;
int startRef = path.indexOf("[");
String current = path;
while (startRef >= 0) {
if (startRef > begin) {
nodes.addAll(splitPath(current.substring(begin, startRef)));
}
int endRef = current.indexOf("]", startRef);
if (endRef > 0) {
String sub = current.substring(startRef + 1, endRef);
if (sub.matches("[0-9]+")) { if (sub.matches("[0-9]+")) {
nodes.add(new ArrayIndexNode(sub)); nodes.add(new ArrayIndexNode(sub));
} }
@ -463,13 +478,11 @@ public class RelaxedDataBinder extends DataBinder {
nodes.add(new MapIndexNode(sub)); nodes.add(new MapIndexNode(sub));
} }
} }
else { begin = endRef + 1;
nodes.add(new PropertyNode(sub)); current = current.substring(begin);
} startRef = current.indexOf("[");
}
} }
} return current;
return nodes;
} }
public void collapseKeys(int index) { public void collapseKeys(int index) {

@ -301,6 +301,14 @@ public class RelaxedDataBinderTests {
assertEquals("123", target.getNested().get("value.foo")); assertEquals("123", target.getNested().get("value.foo"));
} }
@Test
public void testBindNestedMapOfStringReferenced() throws Exception {
TargetWithNestedMapOfString target = new TargetWithNestedMapOfString();
bind(target, "nested.foo: bar\n" + "nested[value.foo]: 123");
assertEquals("bar", target.getNested().get("foo"));
assertEquals("123", target.getNested().get("value.foo"));
}
@Test @Test
public void testBindNestedMapOfEnum() throws Exception { public void testBindNestedMapOfEnum() throws Exception {
this.conversionService = new DefaultConversionService(); this.conversionService = new DefaultConversionService();
@ -317,6 +325,13 @@ public class RelaxedDataBinderTests {
assertEquals("123", target.getNested().get("value")); assertEquals("123", target.getNested().get("value"));
} }
@Test
public void testBindNestedMapBracketReferencedAndPeriods() throws Exception {
TargetWithNestedMap target = new TargetWithNestedMap();
bind(target, "nested[foo]: bar\n" + "nested[foo.value]: 123");
assertEquals("123", target.getNested().get("foo.value"));
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Test @Test
public void testBindDoubleNestedMap() throws Exception { public void testBindDoubleNestedMap() throws Exception {

Loading…
Cancel
Save