Fix binding of overlapping nested maps
When binding a nested map structure, RelaxedDataBinder pre-populates the target object with default empty maps. Previously, when these structures overlapped, each step in pre-population process could potentially overwrite what had come before it. This led to the output of the pre-population process being incomplete which would lead to a binding failure. This commit updates the pre-population process so that it checks to see if a property's value has already been set by an earlier step in the process. If it has been set, the existing value is now reused rather than being overwritten by a new empty map. Fixes #328
This commit is contained in:
parent
8de9890757
commit
ca7201b4b2
|
|
@ -18,6 +18,7 @@ package org.springframework.boot.bind;
|
|||
|
||||
import java.net.InetAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
|
@ -232,11 +233,19 @@ public class RelaxedDataBinder extends DataBinder {
|
|||
&& !descriptor.getType().equals(Object.class)) {
|
||||
return;
|
||||
}
|
||||
String extensionName = path.prefix(index + 1);
|
||||
if (wrapper.isReadableProperty(extensionName)) {
|
||||
Object currentValue = wrapper.getPropertyValue(extensionName);
|
||||
if ((descriptor.isCollection() && currentValue instanceof Collection)
|
||||
|| (!descriptor.isCollection() && currentValue instanceof Map)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Object extend = new LinkedHashMap<String, Object>();
|
||||
if (descriptor.isCollection()) {
|
||||
extend = new ArrayList<Object>();
|
||||
}
|
||||
wrapper.setPropertyValue(path.prefix(index + 1), extend);
|
||||
wrapper.setPropertyValue(extensionName, extend);
|
||||
}
|
||||
|
||||
private String getActualPropertyName(BeanWrapper target, String prefix, String name) {
|
||||
|
|
|
|||
|
|
@ -380,6 +380,22 @@ public class RelaxedDataBinderTests {
|
|||
assertEquals("123", map.get("value"));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testBindOverlappingNestedMaps() throws Exception {
|
||||
Map<String, Object> target = new LinkedHashMap<String, Object>();
|
||||
BindingResult result = bind(target, "a.b.c.d: abc\na.b.c1.d1: efg");
|
||||
assertEquals(0, result.getErrorCount());
|
||||
|
||||
Map<String, Object> a = (Map<String, Object>) target.get("a");
|
||||
Map<String, Object> b = (Map<String, Object>) a.get("b");
|
||||
Map<String, Object> c = (Map<String, Object>) b.get("c");
|
||||
assertEquals("abc", c.get("d"));
|
||||
|
||||
Map<String, Object> c1 = (Map<String, Object>) b.get("c1");
|
||||
assertEquals("efg", c1.get("d1"));
|
||||
}
|
||||
|
||||
private BindingResult bind(Object target, String values) throws Exception {
|
||||
return bind(target, values, null);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue