18
18
19
19
import java .beans .PropertyEditor ;
20
20
import java .lang .annotation .Annotation ;
21
+ import java .lang .reflect .Array ;
21
22
import java .lang .reflect .Constructor ;
22
23
import java .lang .reflect .Field ;
23
24
import java .util .ArrayList ;
24
25
import java .util .Arrays ;
25
- import java .util .Collection ;
26
26
import java .util .Collections ;
27
27
import java .util .HashMap ;
28
28
import java .util .HashSet ;
29
29
import java .util .List ;
30
30
import java .util .Map ;
31
31
import java .util .Optional ;
32
32
import java .util .Set ;
33
+ import java .util .SortedSet ;
34
+ import java .util .TreeSet ;
33
35
import java .util .function .Predicate ;
34
36
35
37
import org .apache .commons .logging .Log ;
49
51
import org .springframework .beans .SimpleTypeConverter ;
50
52
import org .springframework .beans .TypeConverter ;
51
53
import org .springframework .beans .TypeMismatchException ;
54
+ import org .springframework .core .CollectionFactory ;
52
55
import org .springframework .core .KotlinDetector ;
53
56
import org .springframework .core .MethodParameter ;
54
57
import org .springframework .core .ResolvableType ;
@@ -948,11 +951,24 @@ private Object createObject(ResolvableType objectType, String nestedPath, ValueR
948
951
949
952
String paramPath = nestedPath + lookupName ;
950
953
Class <?> paramType = paramTypes [i ];
954
+ ResolvableType resolvableType = ResolvableType .forMethodParameter (param );
955
+
951
956
Object value = valueResolver .resolveValue (paramPath , paramType );
952
957
958
+ if (value == null ) {
959
+ if (List .class .isAssignableFrom (paramType )) {
960
+ value = createList (paramPath , paramType , resolvableType , valueResolver );
961
+ }
962
+ else if (Map .class .isAssignableFrom (paramType )) {
963
+ value = createMap (paramPath , paramType , resolvableType , valueResolver );
964
+ }
965
+ else if (paramType .isArray ()) {
966
+ value = createArray (paramPath , resolvableType , valueResolver );
967
+ }
968
+ }
969
+
953
970
if (value == null && shouldConstructArgument (param ) && hasValuesFor (paramPath , valueResolver )) {
954
- ResolvableType type = ResolvableType .forMethodParameter (param );
955
- args [i ] = createObject (type , paramPath + "." , valueResolver );
971
+ args [i ] = createObject (resolvableType , paramPath + "." , valueResolver );
956
972
}
957
973
else {
958
974
try {
@@ -1019,9 +1035,7 @@ private Object createObject(ResolvableType objectType, String nestedPath, ValueR
1019
1035
*/
1020
1036
protected boolean shouldConstructArgument (MethodParameter param ) {
1021
1037
Class <?> type = param .nestedIfOptional ().getNestedParameterType ();
1022
- return !(BeanUtils .isSimpleValueType (type ) ||
1023
- Collection .class .isAssignableFrom (type ) || Map .class .isAssignableFrom (type ) || type .isArray () ||
1024
- type .getPackageName ().startsWith ("java." ));
1038
+ return !BeanUtils .isSimpleValueType (type ) && !type .getPackageName ().startsWith ("java." );
1025
1039
}
1026
1040
1027
1041
private boolean hasValuesFor (String paramPath , ValueResolver resolver ) {
@@ -1033,6 +1047,82 @@ private boolean hasValuesFor(String paramPath, ValueResolver resolver) {
1033
1047
return false ;
1034
1048
}
1035
1049
1050
+ @ SuppressWarnings ("unchecked" )
1051
+ @ Nullable
1052
+ private <V > List <V > createList (
1053
+ String paramPath , Class <?> paramType , ResolvableType type , ValueResolver valueResolver ) {
1054
+
1055
+ ResolvableType elementType = type .getNested (2 );
1056
+ SortedSet <Integer > indexes = getIndexes (paramPath , valueResolver );
1057
+ if (indexes == null ) {
1058
+ return null ;
1059
+ }
1060
+ int size = (indexes .last () < this .autoGrowCollectionLimit ? indexes .last () + 1 : 0 );
1061
+ List <V > list = (List <V >) CollectionFactory .createCollection (paramType , size );
1062
+ indexes .forEach (i -> list .add (null ));
1063
+ for (int index : indexes ) {
1064
+ list .set (index , (V ) createObject (elementType , paramPath + "[" + index + "]." , valueResolver ));
1065
+ }
1066
+ return list ;
1067
+ }
1068
+
1069
+ @ SuppressWarnings ("unchecked" )
1070
+ @ Nullable
1071
+ private <V > Map <String , V > createMap (
1072
+ String paramPath , Class <?> paramType , ResolvableType type , ValueResolver valueResolver ) {
1073
+
1074
+ ResolvableType elementType = type .getNested (2 );
1075
+ Map <String , V > map = null ;
1076
+ for (String name : valueResolver .getNames ()) {
1077
+ if (!name .startsWith (paramPath + "[" )) {
1078
+ continue ;
1079
+ }
1080
+ int startIdx = paramPath .length () + 1 ;
1081
+ int endIdx = name .indexOf (']' , startIdx );
1082
+ String nestedPath = name .substring (0 , endIdx + 2 );
1083
+ boolean quoted = (endIdx - startIdx > 2 && name .charAt (startIdx ) == '\'' && name .charAt (endIdx - 1 ) == '\'' );
1084
+ String key = (quoted ? name .substring (startIdx + 1 , endIdx - 1 ) : name .substring (startIdx , endIdx ));
1085
+ if (map == null ) {
1086
+ map = CollectionFactory .createMap (paramType , 16 );
1087
+ }
1088
+ if (!map .containsKey (key )) {
1089
+ map .put (key , (V ) createObject (elementType , nestedPath , valueResolver ));
1090
+ }
1091
+ }
1092
+ return map ;
1093
+ }
1094
+
1095
+ @ SuppressWarnings ("unchecked" )
1096
+ @ Nullable
1097
+ private <V > V [] createArray (String paramPath , ResolvableType type , ValueResolver valueResolver ) {
1098
+ ResolvableType elementType = type .getNested (2 );
1099
+ SortedSet <Integer > indexes = getIndexes (paramPath , valueResolver );
1100
+ if (indexes == null ) {
1101
+ return null ;
1102
+ }
1103
+ int size = (indexes .last () < this .autoGrowCollectionLimit ? indexes .last () + 1 : 0 );
1104
+ V [] array = (V []) Array .newInstance (elementType .resolve (), size );
1105
+ for (int index : indexes ) {
1106
+ array [index ] = (V ) createObject (elementType , paramPath + "[" + index + "]." , valueResolver );
1107
+ }
1108
+ return array ;
1109
+ }
1110
+
1111
+ @ Nullable
1112
+ private static SortedSet <Integer > getIndexes (String paramPath , ValueResolver valueResolver ) {
1113
+ SortedSet <Integer > indexes = null ;
1114
+ for (String name : valueResolver .getNames ()) {
1115
+ if (name .startsWith (paramPath + "[" )) {
1116
+ int endIndex = name .indexOf (']' , paramPath .length () + 2 );
1117
+ String rawIndex = name .substring (paramPath .length () + 1 , endIndex );
1118
+ int index = Integer .parseInt (rawIndex );
1119
+ indexes = (indexes != null ? indexes : new TreeSet <>());
1120
+ indexes .add (index );
1121
+ }
1122
+ }
1123
+ return indexes ;
1124
+ }
1125
+
1036
1126
private void validateConstructorArgument (
1037
1127
Class <?> constructorClass , String nestedPath , String name , @ Nullable Object value ) {
1038
1128
0 commit comments