1616
1717package org .springframework .boot .convert ;
1818
19+ import java .util .Collections ;
1920import java .util .LinkedHashSet ;
21+ import java .util .Map ;
22+ import java .util .Objects ;
23+ import java .util .Optional ;
2024import java .util .Set ;
2125
2226import 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 ;
2331import org .springframework .core .convert .ConversionService ;
2432import org .springframework .core .convert .TypeDescriptor ;
33+ import org .springframework .core .convert .converter .ConditionalConverter ;
34+ import org .springframework .core .convert .converter .ConditionalGenericConverter ;
2535import org .springframework .core .convert .converter .Converter ;
2636import org .springframework .core .convert .converter .ConverterRegistry ;
2737import org .springframework .core .convert .converter .GenericConverter ;
4656 * against registry instance.
4757 *
4858 * @author Phillip Webb
59+ * @author 郭 世雄
4960 * @since 2.0.0
5061 */
5162public class ApplicationConversionService extends FormattingConversionService {
@@ -188,17 +199,18 @@ public static void addApplicationFormatters(FormatterRegistry registry) {
188199 * @since 2.2.0
189200 */
190201 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 ();
197209 if (bean instanceof GenericConverter ) {
198210 registry .addConverter ((GenericConverter ) bean );
199211 }
200212 else if (bean instanceof Converter ) {
201- registry . addConverter (( Converter <?, ?>) bean );
213+ addConverter (registry , beanFactory , entity );
202214 }
203215 else if (bean instanceof Formatter ) {
204216 registry .addFormatter ((Formatter <?>) bean );
@@ -212,4 +224,120 @@ else if (bean instanceof Parser) {
212224 }
213225 }
214226
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+
215343}
0 commit comments