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) {
|
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);
|
|
||||||
if (sub.matches("[0-9]+")) {
|
|
||||||
nodes.add(new ArrayIndexNode(sub));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
nodes.add(new MapIndexNode(sub));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
nodes.add(new PropertyNode(sub));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nodes;
|
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) {
|
public void collapseKeys(int index) {
|
||||||
List<PathNode> revised = new ArrayList<PathNode>();
|
List<PathNode> revised = new ArrayList<PathNode>();
|
||||||
for (int i = 0; i < index; i++) {
|
for (int i = 0; i < index; i++) {
|
||||||
|
|
|
||||||
|
|
@ -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…
Reference in New Issue