16
16
17
17
package org .springframework .boot .convert ;
18
18
19
+ import java .util .Collections ;
19
20
import java .util .LinkedHashSet ;
21
+ import java .util .Map ;
22
+ import java .util .Objects ;
23
+ import java .util .Optional ;
20
24
import java .util .Set ;
21
25
22
26
import org .springframework .beans .factory .ListableBeanFactory ;
27
+ import org .springframework .beans .factory .config .BeanDefinition ;
28
+ import org .springframework .beans .factory .config .ConfigurableListableBeanFactory ;
29
+ import org .springframework .context .ConfigurableApplicationContext ;
30
+ import org .springframework .core .ResolvableType ;
23
31
import org .springframework .core .convert .ConversionService ;
24
32
import org .springframework .core .convert .TypeDescriptor ;
33
+ import org .springframework .core .convert .converter .ConditionalConverter ;
34
+ import org .springframework .core .convert .converter .ConditionalGenericConverter ;
25
35
import org .springframework .core .convert .converter .Converter ;
26
36
import org .springframework .core .convert .converter .ConverterRegistry ;
27
37
import org .springframework .core .convert .converter .GenericConverter ;
46
56
* against registry instance.
47
57
*
48
58
* @author Phillip Webb
59
+ * @author 郭 世雄
49
60
* @since 2.0.0
50
61
*/
51
62
public class ApplicationConversionService extends FormattingConversionService {
@@ -188,17 +199,18 @@ public static void addApplicationFormatters(FormatterRegistry registry) {
188
199
* @since 2.2.0
189
200
*/
190
201
public static void addBeans (FormatterRegistry registry , ListableBeanFactory beanFactory ) {
191
- Set <Object > beans = new LinkedHashSet <>();
192
- beans .addAll (beanFactory .getBeansOfType (GenericConverter .class ).values ());
193
- beans .addAll (beanFactory .getBeansOfType (Converter .class ).values ());
194
- beans .addAll (beanFactory .getBeansOfType (Printer .class ).values ());
195
- beans .addAll (beanFactory .getBeansOfType (Parser .class ).values ());
196
- for (Object bean : beans ) {
202
+ Set <Map .Entry <String , ?>> entries = new LinkedHashSet <>();
203
+ entries .addAll (beanFactory .getBeansOfType (GenericConverter .class ).entrySet ());
204
+ entries .addAll (beanFactory .getBeansOfType (Converter .class ).entrySet ());
205
+ entries .addAll (beanFactory .getBeansOfType (Printer .class ).entrySet ());
206
+ entries .addAll (beanFactory .getBeansOfType (Parser .class ).entrySet ());
207
+ for (Map .Entry <String , ?> entity : entries ) {
208
+ Object bean = entity .getValue ();
197
209
if (bean instanceof GenericConverter ) {
198
210
registry .addConverter ((GenericConverter ) bean );
199
211
}
200
212
else if (bean instanceof Converter ) {
201
- registry . addConverter (( Converter <?, ?>) bean );
213
+ addConverter (registry , beanFactory , entity );
202
214
}
203
215
else if (bean instanceof Formatter ) {
204
216
registry .addFormatter ((Formatter <?>) bean );
@@ -212,4 +224,120 @@ else if (bean instanceof Parser) {
212
224
}
213
225
}
214
226
227
+ private static void addConverter (FormatterRegistry registry , ListableBeanFactory beanFactory ,
228
+ Map .Entry <String , ?> entity ) {
229
+ try {
230
+ registry .addConverter ((Converter <?, ?>) entity .getValue ());
231
+ }
232
+ catch (IllegalArgumentException ex ) {
233
+ boolean success = tryAddMethodSignatureGenericsConverter (registry , beanFactory , entity );
234
+ if (!success ) {
235
+ throw ex ;
236
+ }
237
+ }
238
+ }
239
+
240
+ private static boolean tryAddMethodSignatureGenericsConverter (FormatterRegistry registry ,
241
+ ListableBeanFactory beanFactory , Map .Entry <String , ?> entity ) {
242
+ ListableBeanFactory bf = beanFactory ;
243
+ if (bf instanceof ConfigurableApplicationContext ) {
244
+ bf = ((ConfigurableApplicationContext ) bf ).getBeanFactory ();
245
+ }
246
+ if (bf instanceof ConfigurableListableBeanFactory ) {
247
+ ConfigurableListableBeanFactory clbf = (ConfigurableListableBeanFactory ) bf ;
248
+ ConverterAdapter adapter = getConverterAdapter (clbf , entity );
249
+ if (!Objects .isNull (adapter )) {
250
+ registry .addConverter (adapter );
251
+ return true ;
252
+ }
253
+ }
254
+ return false ;
255
+ }
256
+
257
+ private static ConverterAdapter getConverterAdapter (ConfigurableListableBeanFactory beanFactory ,
258
+ Map .Entry <String , ?> beanEntity ) {
259
+ BeanDefinition beanDefinition = beanFactory .getMergedBeanDefinition (beanEntity .getKey ());
260
+ ResolvableType resolvableType = beanDefinition .getResolvableType ();
261
+ ResolvableType [] types = resolvableType .getGenerics ();
262
+ if (types .length < 2 ) {
263
+ return null ;
264
+ }
265
+ return new ConverterAdapter ((Converter <?, ?>) beanEntity .getValue (), types [0 ], types [1 ]);
266
+ }
267
+
268
+ /**
269
+ * Adapts a {@link Converter} to a {@link GenericConverter}.
270
+ * <p>
271
+ * Reference from
272
+ * {@link org.springframework.core.convert.support.GenericConversionService.ConverterAdapter}
273
+ */
274
+ @ SuppressWarnings ("unchecked" )
275
+ private static final class ConverterAdapter implements ConditionalGenericConverter {
276
+
277
+ private final Converter <Object , Object > converter ;
278
+
279
+ private final ConvertiblePair typeInfo ;
280
+
281
+ private final ResolvableType targetType ;
282
+
283
+ ConverterAdapter (Converter <?, ?> converter , ResolvableType sourceType , ResolvableType targetType ) {
284
+ this .converter = (Converter <Object , Object >) converter ;
285
+ this .typeInfo = new ConvertiblePair (sourceType .toClass (), targetType .toClass ());
286
+ this .targetType = targetType ;
287
+ }
288
+
289
+ @ Override
290
+ public Set <ConvertiblePair > getConvertibleTypes () {
291
+ return Collections .singleton (this .typeInfo );
292
+ }
293
+
294
+ @ Override
295
+ public boolean matches (TypeDescriptor sourceType , TypeDescriptor targetType ) {
296
+ // Check raw type first...
297
+ if (this .typeInfo .getTargetType () != targetType .getObjectType ()) {
298
+ return false ;
299
+ }
300
+ // Full check for complex generic type match required?
301
+ ResolvableType rt = targetType .getResolvableType ();
302
+ if (!(rt .getType () instanceof Class ) && !rt .isAssignableFrom (this .targetType )
303
+ && !this .targetType .hasUnresolvableGenerics ()) {
304
+ return false ;
305
+ }
306
+ return !(this .converter instanceof ConditionalConverter )
307
+ || ((ConditionalConverter ) this .converter ).matches (sourceType , targetType );
308
+ }
309
+
310
+ @ Override
311
+ public Object convert (Object source , TypeDescriptor sourceType , TypeDescriptor targetType ) {
312
+ if (source == null ) {
313
+ return convertNullSource (sourceType , targetType );
314
+ }
315
+ return this .converter .convert (source );
316
+ }
317
+
318
+ @ Override
319
+ public String toString () {
320
+ return (this .typeInfo + " : " + this .converter );
321
+ }
322
+
323
+ /**
324
+ * Template method to convert a {@code null} source.
325
+ * <p>
326
+ * The default implementation returns {@code null} or the Java 8
327
+ * {@link java.util.Optional#empty()} instance if the target type is
328
+ * {@code java.util.Optional}. Subclasses may override this to return custom
329
+ * {@code null} objects for specific target types.
330
+ * @param sourceType the source type to convert from
331
+ * @param targetType the target type to convert to
332
+ * @return the converted null object
333
+ */
334
+ private Object convertNullSource (TypeDescriptor sourceType , TypeDescriptor targetType ) {
335
+ if (targetType .getObjectType () == Optional .class ) {
336
+ return Optional .empty ();
337
+ }
338
+ return null ;
339
+ }
340
+
341
+ }
342
+
215
343
}
0 commit comments