Skip to content

Commit

Permalink
Nested list/map/array with constructor binding
Browse files Browse the repository at this point in the history
Closes gh-34305
  • Loading branch information
rstoyanchev committed Feb 11, 2025
1 parent 4591a67 commit 9f55296
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1154,23 +1154,36 @@ private static SortedSet<Integer> getIndexes(String paramPath, ValueResolver val
@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;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,34 @@ void simpleArrayBinding() {
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) {
Expand Down Expand Up @@ -317,6 +345,14 @@ private record IntegerArrayRecord(Integer[] integerArray) {
}


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
Expand Down

0 comments on commit 9f55296

Please sign in to comment.