|
|
|
@ -142,6 +142,10 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter { |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
protected static final Log logger = LogFactory.getLog(DataBinder.class); |
|
|
|
protected static final Log logger = LogFactory.getLog(DataBinder.class); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Internal constant for constructor binding via "[]". */ |
|
|
|
|
|
|
|
private static final int NO_INDEX = -1; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private @Nullable Object target; |
|
|
|
private @Nullable Object target; |
|
|
|
|
|
|
|
|
|
|
|
@Nullable ResolvableType targetType; |
|
|
|
@Nullable ResolvableType targetType; |
|
|
|
@ -1028,15 +1032,17 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter { |
|
|
|
return null; |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int size = (indexes.last() < this.autoGrowCollectionLimit ? indexes.last() + 1 : 0); |
|
|
|
int lastIndex = Math.max(indexes.last(), 0); |
|
|
|
|
|
|
|
int size = (lastIndex < this.autoGrowCollectionLimit ? lastIndex + 1 : 0); |
|
|
|
List<?> list = (List<?>) CollectionFactory.createCollection(paramType, size); |
|
|
|
List<?> list = (List<?>) CollectionFactory.createCollection(paramType, size); |
|
|
|
for (int i = 0; i < size; i++) { |
|
|
|
for (int i = 0; i < size; i++) { |
|
|
|
list.add(null); |
|
|
|
list.add(null); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
for (int index : indexes) { |
|
|
|
for (int index : indexes) { |
|
|
|
String indexedPath = paramPath + "[" + index + "]"; |
|
|
|
String indexedPath = paramPath + "[" + (index != NO_INDEX ? index : "") + "]"; |
|
|
|
list.set(index, createIndexedValue(paramPath, paramType, elementType, indexedPath, valueResolver)); |
|
|
|
list.set(Math.max(index, 0), |
|
|
|
|
|
|
|
createIndexedValue(paramPath, paramType, elementType, indexedPath, valueResolver)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return list; |
|
|
|
return list; |
|
|
|
@ -1078,12 +1084,14 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter { |
|
|
|
return null; |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int size = (indexes.last() < this.autoGrowCollectionLimit ? indexes.last() + 1: 0); |
|
|
|
int lastIndex = Math.max(indexes.last(), 0); |
|
|
|
|
|
|
|
int size = (lastIndex < this.autoGrowCollectionLimit ? lastIndex + 1: 0); |
|
|
|
@Nullable V[] array = (V[]) Array.newInstance(elementType.resolve(), size); |
|
|
|
@Nullable V[] array = (V[]) Array.newInstance(elementType.resolve(), size); |
|
|
|
|
|
|
|
|
|
|
|
for (int index : indexes) { |
|
|
|
for (int index : indexes) { |
|
|
|
String indexedPath = paramPath + "[" + index + "]"; |
|
|
|
String indexedPath = paramPath + "[" + (index != NO_INDEX ? index : "") + "]"; |
|
|
|
array[index] = createIndexedValue(paramPath, paramType, elementType, indexedPath, valueResolver); |
|
|
|
array[Math.max(index, 0)] = |
|
|
|
|
|
|
|
createIndexedValue(paramPath, paramType, elementType, indexedPath, valueResolver); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return array; |
|
|
|
return array; |
|
|
|
@ -1093,13 +1101,20 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter { |
|
|
|
SortedSet<Integer> indexes = null; |
|
|
|
SortedSet<Integer> indexes = null; |
|
|
|
for (String name : valueResolver.getNames()) { |
|
|
|
for (String name : valueResolver.getNames()) { |
|
|
|
if (name.startsWith(paramPath + "[")) { |
|
|
|
if (name.startsWith(paramPath + "[")) { |
|
|
|
int endIndex = name.indexOf(']', paramPath.length() + 2); |
|
|
|
int index; |
|
|
|
String rawIndex = name.substring(paramPath.length() + 1, endIndex); |
|
|
|
if (paramPath.length() + 2 == name.length()) { |
|
|
|
if (StringUtils.hasLength(rawIndex)) { |
|
|
|
if (!name.endsWith("[]")) { |
|
|
|
int index = Integer.parseInt(rawIndex); |
|
|
|
continue; |
|
|
|
indexes = (indexes != null ? indexes : new TreeSet<>()); |
|
|
|
} |
|
|
|
indexes.add(index); |
|
|
|
index = NO_INDEX; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
|
|
|
|
int endIndex = name.indexOf(']', paramPath.length() + 2); |
|
|
|
|
|
|
|
String indexValue = name.substring(paramPath.length() + 1, endIndex); |
|
|
|
|
|
|
|
index = Integer.parseInt(indexValue); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
indexes = (indexes != null ? indexes : new TreeSet<>()); |
|
|
|
|
|
|
|
indexes.add(index); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
return indexes; |
|
|
|
return indexes; |
|
|
|
@ -1107,23 +1122,36 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter { |
|
|
|
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked") |
|
|
|
@SuppressWarnings("unchecked") |
|
|
|
private <V> @Nullable V createIndexedValue( |
|
|
|
private <V> @Nullable V createIndexedValue( |
|
|
|
String paramPath, Class<?> paramType, ResolvableType elementType, |
|
|
|
String paramPath, Class<?> containerType, ResolvableType elementType, |
|
|
|
String indexedPath, ValueResolver valueResolver) { |
|
|
|
String indexedPath, ValueResolver valueResolver) { |
|
|
|
|
|
|
|
|
|
|
|
Object value = null; |
|
|
|
Object value = null; |
|
|
|
Class<?> elementClass = elementType.resolve(Object.class); |
|
|
|
Class<?> elementClass = elementType.resolve(Object.class); |
|
|
|
Object rawValue = valueResolver.resolveValue(indexedPath, elementClass); |
|
|
|
|
|
|
|
if (rawValue != null) { |
|
|
|
if (List.class.isAssignableFrom(elementClass)) { |
|
|
|
try { |
|
|
|
value = createList(indexedPath, elementClass, elementType, valueResolver); |
|
|
|
value = convertIfNecessary(rawValue, elementClass); |
|
|
|
} |
|
|
|
} |
|
|
|
else if (Map.class.isAssignableFrom(elementClass)) { |
|
|
|
catch (TypeMismatchException ex) { |
|
|
|
value = createMap(indexedPath, elementClass, elementType, valueResolver); |
|
|
|
handleTypeMismatchException(ex, paramPath, paramType, rawValue); |
|
|
|
} |
|
|
|
} |
|
|
|
else if (elementClass.isArray()) { |
|
|
|
|
|
|
|
value = createArray(indexedPath, elementClass, elementType, valueResolver); |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
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; |
|
|
|
return (V) value; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|