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 .core .ResolvableType ;
2330import org .springframework .core .convert .ConversionService ;
31+ import org .springframework .core .convert .TypeDescriptor ;
32+ import org .springframework .core .convert .converter .ConditionalConverter ;
33+ import org .springframework .core .convert .converter .ConditionalGenericConverter ;
2434import org .springframework .core .convert .converter .Converter ;
2535import org .springframework .core .convert .converter .ConverterRegistry ;
2636import org .springframework .core .convert .converter .GenericConverter ;
4454 * against registry instance.
4555 *
4656 * @author Phillip Webb
57+ * @author 郭世雄 Viviel
4758 * @since 2.0.0
4859 */
4960public class ApplicationConversionService extends FormattingConversionService {
@@ -157,17 +168,30 @@ public static void addApplicationFormatters(FormatterRegistry registry) {
157168 * @since 2.2.0
158169 */
159170 public static void addBeans (FormatterRegistry registry , ListableBeanFactory beanFactory ) {
160- Set <Object > beans = new LinkedHashSet <>();
161- beans .addAll (beanFactory .getBeansOfType (GenericConverter .class ).values ());
162- beans .addAll (beanFactory .getBeansOfType (Converter .class ).values ());
163- beans .addAll (beanFactory .getBeansOfType (Printer .class ).values ());
164- beans .addAll (beanFactory .getBeansOfType (Parser .class ).values ());
165- for (Object bean : beans ) {
171+ Set <Map .Entry <String , ?>> entries = new LinkedHashSet <>();
172+ entries .addAll (beanFactory .getBeansOfType (GenericConverter .class ).entrySet ());
173+ entries .addAll (beanFactory .getBeansOfType (Converter .class ).entrySet ());
174+ entries .addAll (beanFactory .getBeansOfType (Printer .class ).entrySet ());
175+ entries .addAll (beanFactory .getBeansOfType (Parser .class ).entrySet ());
176+ for (Map .Entry <String , ?> entity : entries ) {
177+ Object bean = entity .getValue ();
166178 if (bean instanceof GenericConverter ) {
167179 registry .addConverter ((GenericConverter ) bean );
168180 }
169181 else if (bean instanceof Converter ) {
170- registry .addConverter ((Converter <?, ?>) bean );
182+ if (beanFactory instanceof ConfigurableListableBeanFactory ) {
183+ ConverterAdapter adapter = getConverterAdapter ((ConfigurableListableBeanFactory ) beanFactory ,
184+ entity );
185+ if (!Objects .isNull (adapter )) {
186+ registry .addConverter (adapter );
187+ }
188+ else {
189+ registry .addConverter ((Converter <?, ?>) bean );
190+ }
191+ }
192+ else {
193+ registry .addConverter ((Converter <?, ?>) bean );
194+ }
171195 }
172196 else if (bean instanceof Formatter ) {
173197 registry .addFormatter ((Formatter <?>) bean );
@@ -181,4 +205,87 @@ else if (bean instanceof Parser) {
181205 }
182206 }
183207
208+ private static ConverterAdapter getConverterAdapter (ConfigurableListableBeanFactory beanFactory ,
209+ Map .Entry <String , ?> beanEntity ) {
210+ BeanDefinition beanDefinition = beanFactory .getBeanDefinition (beanEntity .getKey ());
211+ ResolvableType resolvableType = beanDefinition .getResolvableType ();
212+ ResolvableType [] types = resolvableType .getGenerics ();
213+ if (types .length < 2 ) {
214+ return null ;
215+ }
216+ return new ConverterAdapter ((Converter <?, ?>) beanEntity .getValue (), types [0 ], types [1 ]);
217+ }
218+
219+ /**
220+ * Adapts a {@link Converter} to a {@link GenericConverter}.
221+ */
222+ @ SuppressWarnings ("unchecked" )
223+ private static final class ConverterAdapter implements ConditionalGenericConverter {
224+
225+ private final Converter <Object , Object > converter ;
226+
227+ private final ConvertiblePair typeInfo ;
228+
229+ private final ResolvableType targetType ;
230+
231+ ConverterAdapter (Converter <?, ?> converter , ResolvableType sourceType , ResolvableType targetType ) {
232+ this .converter = (Converter <Object , Object >) converter ;
233+ this .typeInfo = new ConvertiblePair (sourceType .toClass (), targetType .toClass ());
234+ this .targetType = targetType ;
235+ }
236+
237+ @ Override
238+ public Set <ConvertiblePair > getConvertibleTypes () {
239+ return Collections .singleton (this .typeInfo );
240+ }
241+
242+ @ Override
243+ public boolean matches (TypeDescriptor sourceType , TypeDescriptor targetType ) {
244+ // Check raw type first...
245+ if (this .typeInfo .getTargetType () != targetType .getObjectType ()) {
246+ return false ;
247+ }
248+ // Full check for complex generic type match required?
249+ ResolvableType rt = targetType .getResolvableType ();
250+ if (!(rt .getType () instanceof Class ) && !rt .isAssignableFrom (this .targetType )
251+ && !this .targetType .hasUnresolvableGenerics ()) {
252+ return false ;
253+ }
254+ return !(this .converter instanceof ConditionalConverter )
255+ || ((ConditionalConverter ) this .converter ).matches (sourceType , targetType );
256+ }
257+
258+ @ Override
259+ public Object convert (Object source , TypeDescriptor sourceType , TypeDescriptor targetType ) {
260+ if (source == null ) {
261+ return convertNullSource (sourceType , targetType );
262+ }
263+ return this .converter .convert (source );
264+ }
265+
266+ @ Override
267+ public String toString () {
268+ return (this .typeInfo + " : " + this .converter );
269+ }
270+
271+ /**
272+ * Template method to convert a {@code null} source.
273+ * <p>
274+ * The default implementation returns {@code null} or the Java 8
275+ * {@link java.util.Optional#empty()} instance if the target type is
276+ * {@code java.util.Optional}. Subclasses may override this to return custom
277+ * {@code null} objects for specific target types.
278+ * @param sourceType the source type to convert from
279+ * @param targetType the target type to convert to
280+ * @return the converted null object
281+ */
282+ private Object convertNullSource (TypeDescriptor sourceType , TypeDescriptor targetType ) {
283+ if (targetType .getObjectType () == Optional .class ) {
284+ return Optional .empty ();
285+ }
286+ return null ;
287+ }
288+
289+ }
290+
184291}
0 commit comments