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)
This commit is contained in:
parent
44a708ea5c
commit
ff637d3aaa
|
|
@ -451,27 +451,40 @@ public class RelaxedDataBinder extends DataBinder {
|
|||
|
||||
private List<PathNode> splitPath(String path) {
|
||||
List<PathNode> nodes = new ArrayList<PathNode>();
|
||||
for (String name : StringUtils.delimitedListToStringArray(path, ".")) {
|
||||
for (String sub : StringUtils.delimitedListToStringArray(name, "[")) {
|
||||
if (StringUtils.hasText(sub)) {
|
||||
if (sub.endsWith("]")) {
|
||||
sub = sub.substring(0, sub.length() - 1);
|
||||
if (sub.matches("[0-9]+")) {
|
||||
nodes.add(new ArrayIndexNode(sub));
|
||||
}
|
||||
else {
|
||||
nodes.add(new MapIndexNode(sub));
|
||||
}
|
||||
}
|
||||
else {
|
||||
nodes.add(new PropertyNode(sub));
|
||||
}
|
||||
}
|
||||
String current = extractIndexedPaths(path, nodes);
|
||||
for (String name : StringUtils.delimitedListToStringArray(current, ".")) {
|
||||
if (StringUtils.hasText(name)) {
|
||||
nodes.add(new PropertyNode(name));
|
||||
}
|
||||
}
|
||||
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]+")) {
|
||||
nodes.add(new ArrayIndexNode(sub));
|
||||
}
|
||||
else {
|
||||
nodes.add(new MapIndexNode(sub));
|
||||
}
|
||||
}
|
||||
begin = endRef + 1;
|
||||
current = current.substring(begin);
|
||||
startRef = current.indexOf("[");
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
public void collapseKeys(int index) {
|
||||
List<PathNode> revised = new ArrayList<PathNode>();
|
||||
for (int i = 0; i < index; i++) {
|
||||
|
|
|
|||
|
|
@ -301,6 +301,14 @@ public class RelaxedDataBinderTests {
|
|||
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
|
||||
public void testBindNestedMapOfEnum() throws Exception {
|
||||
this.conversionService = new DefaultConversionService();
|
||||
|
|
@ -317,6 +325,13 @@ public class RelaxedDataBinderTests {
|
|||
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")
|
||||
@Test
|
||||
public void testBindDoubleNestedMap() throws Exception {
|
||||
|
|
|
|||
Loading…
Reference in New Issue