19
19
import java .lang .reflect .Constructor ;
20
20
import java .lang .reflect .Modifier ;
21
21
import java .lang .reflect .Parameter ;
22
+ import java .lang .reflect .Type ;
22
23
import java .util .ArrayList ;
23
- import java .util .Collections ;
24
- import java .util .HashMap ;
25
24
import java .util .LinkedHashMap ;
26
25
import java .util .List ;
27
26
import java .util .Map ;
28
27
28
+ import kotlin .reflect .KFunction ;
29
+ import kotlin .reflect .KParameter ;
30
+ import kotlin .reflect .jvm .ReflectJvmMapping ;
31
+
29
32
import org .springframework .beans .BeanUtils ;
30
33
import org .springframework .boot .context .properties .ConfigurationPropertyDefaultValue ;
31
34
import org .springframework .boot .context .properties .source .ConfigurationPropertyName ;
@@ -42,18 +45,6 @@ class ConstructorParametersBinder implements BeanBinder {
42
45
43
46
private static boolean KOTLIN_PRESENT = KotlinDetector .isKotlinPresent ();
44
47
45
- private static final Map <Class <?>, Object > DEFAULT_TYPE_VALUES ;
46
-
47
- static {
48
- Map <Class <?>, Object > values = new HashMap <>();
49
- values .put (boolean .class , false );
50
- values .put (byte .class , (byte ) 0 );
51
- values .put (short .class , (short ) 0 );
52
- values .put (int .class , 0 );
53
- values .put (long .class , (long ) 0 );
54
- DEFAULT_TYPE_VALUES = Collections .unmodifiableMap (values );
55
- }
56
-
57
48
@ Override
58
49
@ SuppressWarnings ("unchecked" )
59
50
public <T > T bind (ConfigurationPropertyName name , Bindable <T > target ,
@@ -72,14 +63,14 @@ private List<Object> bind(BeanPropertyBinder propertyBinder, Bean bean,
72
63
for (ConstructorParameter parameter : bean .getParameters ().values ()) {
73
64
Object bound = bind (parameter , propertyBinder );
74
65
if (bound == null ) {
75
- bound = getDefaultValue (parameter , bean , converter );
66
+ bound = getDefaultValue (parameter , converter );
76
67
}
77
68
boundParams .add (bound );
78
69
}
79
70
return boundParams ;
80
71
}
81
72
82
- private Object getDefaultValue (ConstructorParameter parameter , Bean bean ,
73
+ private Object getDefaultValue (ConstructorParameter parameter ,
83
74
BindConverter converter ) {
84
75
if (parameter .getDefaultValue () != null ) {
85
76
return converter .convert (parameter .getDefaultValue (), parameter .getType (),
@@ -88,7 +79,7 @@ private Object getDefaultValue(ConstructorParameter parameter, Bean bean,
88
79
else {
89
80
Class <?> resolve = parameter .getType ().resolve ();
90
81
if (resolve != null && resolve .isPrimitive ()) {
91
- return ( bean . kotlinType ) ? null : DEFAULT_TYPE_VALUES . get ( resolve ) ;
82
+ return null ;
92
83
}
93
84
}
94
85
return null ;
@@ -103,15 +94,12 @@ private Object bind(ConstructorParameter parameter,
103
94
104
95
private static final class Bean {
105
96
106
- private final boolean kotlinType ;
107
-
108
97
private final Constructor <?> constructor ;
109
98
110
99
private final Map <String , ConstructorParameter > parameters ;
111
100
112
- private Bean (boolean kotlinType , Constructor <?> constructor ,
101
+ private Bean (Constructor <?> constructor ,
113
102
Map <String , ConstructorParameter > parameters ) {
114
- this .kotlinType = kotlinType ;
115
103
this .constructor = constructor ;
116
104
this .parameters = parameters ;
117
105
}
@@ -129,20 +117,37 @@ public static Bean get(Bindable<?> bindable) {
129
117
.findPrimaryConstructor (type );
130
118
if (primaryConstructor != null
131
119
&& primaryConstructor .getParameterCount () > 0 ) {
132
- return new Bean (true , primaryConstructor ,
133
- parseParameters (primaryConstructor ));
120
+ return KotlinBeanProvider .get (primaryConstructor );
134
121
}
135
122
}
136
123
else {
137
124
Constructor <?>[] constructors = type .getDeclaredConstructors ();
138
125
if (constructors .length == 1 && constructors [0 ].getParameterCount () > 0 ) {
139
- Constructor <?> constructor = constructors [0 ];
140
- return new Bean (false , constructor , parseParameters (constructor ));
126
+ return SimpleBeanProvider .get (constructors [0 ]);
141
127
}
142
128
}
143
129
return null ;
144
130
}
145
131
132
+ public Map <String , ConstructorParameter > getParameters () {
133
+ return this .parameters ;
134
+ }
135
+
136
+ public Constructor <?> getConstructor () {
137
+ return this .constructor ;
138
+ }
139
+
140
+ }
141
+
142
+ /**
143
+ * A simple bean provider that uses `-parameters` to extract the parameter names.
144
+ */
145
+ private static class SimpleBeanProvider {
146
+
147
+ public static Bean get (Constructor <?> constructor ) {
148
+ return new Bean (constructor , parseParameters (constructor ));
149
+ }
150
+
146
151
private static Map <String , ConstructorParameter > parseParameters (
147
152
Constructor <?> constructor ) {
148
153
Map <String , ConstructorParameter > parameters = new LinkedHashMap <>();
@@ -160,12 +165,37 @@ private static Map<String, ConstructorParameter> parseParameters(
160
165
return parameters ;
161
166
}
162
167
163
- public Map <String , ConstructorParameter > getParameters () {
164
- return this .parameters ;
168
+ }
169
+
170
+ /**
171
+ * A bean provider for a Kotlin class. Uses the Kotlin constructor to extract the
172
+ * parameter names.
173
+ */
174
+ private static class KotlinBeanProvider {
175
+
176
+ public static Bean get (Constructor <?> constructor ) {
177
+ KFunction <?> kotlinConstructor = ReflectJvmMapping
178
+ .getKotlinFunction (constructor );
179
+ if (kotlinConstructor != null ) {
180
+ return new Bean (constructor , parseParameters (kotlinConstructor ));
181
+ }
182
+ else {
183
+ return SimpleBeanProvider .get (constructor );
184
+ }
165
185
}
166
186
167
- public Constructor <?> getConstructor () {
168
- return this .constructor ;
187
+ private static Map <String , ConstructorParameter > parseParameters (
188
+ KFunction <?> constructor ) {
189
+ Map <String , ConstructorParameter > parameters = new LinkedHashMap <>();
190
+ for (KParameter parameter : constructor .getParameters ()) {
191
+ String name = parameter .getName ();
192
+ Type type = ReflectJvmMapping .getJavaType (parameter .getType ());
193
+ Annotation [] annotations = parameter .getAnnotations ()
194
+ .toArray (new Annotation [0 ]);
195
+ parameters .computeIfAbsent (name , (s ) -> new ConstructorParameter (name ,
196
+ ResolvableType .forType (type ), annotations , null ));
197
+ }
198
+ return parameters ;
169
199
}
170
200
171
201
}
0 commit comments