Nested list/map/array with constructor binding
Closes gh-34305
This commit is contained in:
parent
4591a67641
commit
9f55296049
|
@ -1154,23 +1154,36 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter {
|
|||
@SuppressWarnings("unchecked")
|
||||
@Nullable
|
||||
private <V> V createIndexedValue(
|
||||
String paramPath, Class<?> paramType, ResolvableType elementType,
|
||||
String paramPath, Class<?> containerType, ResolvableType elementType,
|
||||
String indexedPath, ValueResolver valueResolver) {
|
||||
|
||||
Object value = null;
|
||||
Class<?> elementClass = elementType.resolve(Object.class);
|
||||
Object rawValue = valueResolver.resolveValue(indexedPath, elementClass);
|
||||
if (rawValue != null) {
|
||||
try {
|
||||
value = convertIfNecessary(rawValue, elementClass);
|
||||
}
|
||||
catch (TypeMismatchException ex) {
|
||||
handleTypeMismatchException(ex, paramPath, paramType, rawValue);
|
||||
}
|
||||
|
||||
if (List.class.isAssignableFrom(elementClass)) {
|
||||
value = createList(indexedPath, elementClass, elementType, valueResolver);
|
||||
}
|
||||
else if (Map.class.isAssignableFrom(elementClass)) {
|
||||
value = createMap(indexedPath, elementClass, elementType, valueResolver);
|
||||
}
|
||||
else if (elementClass.isArray()) {
|
||||
value = createArray(indexedPath, elementClass, elementType, valueResolver);
|
||||
}
|
||||
else {
|
||||
value = createObject(elementType, indexedPath + ".", valueResolver);
|
||||
Object rawValue = valueResolver.resolveValue(indexedPath, elementClass);
|
||||
if (rawValue != null) {
|
||||
try {
|
||||
value = convertIfNecessary(rawValue, elementClass);
|
||||
}
|
||||
catch (TypeMismatchException ex) {
|
||||
handleTypeMismatchException(ex, paramPath, containerType, rawValue);
|
||||
}
|
||||
}
|
||||
else {
|
||||
value = createObject(elementType, indexedPath + ".", valueResolver);
|
||||
}
|
||||
}
|
||||
|
||||
return (V) value;
|
||||
}
|
||||
|
||||
|
|
|
@ -221,6 +221,34 @@ class DataBinderConstructTests {
|
|||
assertThat(target.integerArray()).containsExactly(1, 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void nestedListWithinMap() {
|
||||
MapValueResolver valueResolver = new MapValueResolver(Map.of(
|
||||
"integerListMap[a][0]", "1", "integerListMap[a][1]", "2",
|
||||
"integerListMap[b][0]", "3", "integerListMap[b][1]", "4"));
|
||||
|
||||
DataBinder binder = initDataBinder(IntegerListMapRecord.class);
|
||||
binder.construct(valueResolver);
|
||||
|
||||
IntegerListMapRecord target = getTarget(binder);
|
||||
assertThat(target.integerListMap().get("a")).containsExactly(1, 2);
|
||||
assertThat(target.integerListMap().get("b")).containsExactly(3, 4);
|
||||
}
|
||||
|
||||
@Test
|
||||
void nestedMapWithinList() {
|
||||
MapValueResolver valueResolver = new MapValueResolver(Map.of(
|
||||
"integerMapList[0][a]", "1", "integerMapList[0][b]", "2",
|
||||
"integerMapList[1][a]", "3", "integerMapList[1][b]", "4"));
|
||||
|
||||
DataBinder binder = initDataBinder(IntegerMapListRecord.class);
|
||||
binder.construct(valueResolver);
|
||||
|
||||
IntegerMapListRecord target = getTarget(binder);
|
||||
assertThat(target.integerMapList().get(0)).containsOnly(Map.entry("a", 1), Map.entry("b", 2));
|
||||
assertThat(target.integerMapList().get(1)).containsOnly(Map.entry("a", 3), Map.entry("b", 4));
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
private static DataBinder initDataBinder(Class<?> targetType) {
|
||||
|
@ -317,6 +345,14 @@ class DataBinderConstructTests {
|
|||
}
|
||||
|
||||
|
||||
private record IntegerMapListRecord(List<Map<String, Integer>> integerMapList) {
|
||||
}
|
||||
|
||||
|
||||
private record IntegerListMapRecord(Map<String, List<Integer>> integerListMap) {
|
||||
}
|
||||
|
||||
|
||||
private record MapValueResolver(Map<String, Object> map) implements DataBinder.ValueResolver {
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in New Issue