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 .core .ResolvableType ;
23
30
import 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 ;
24
34
import org .springframework .core .convert .converter .Converter ;
25
35
import org .springframework .core .convert .converter .ConverterRegistry ;
26
36
import org .springframework .core .convert .converter .GenericConverter ;
44
54
* against registry instance.
45
55
*
46
56
* @author Phillip Webb
57
+ * @author 郭世雄 Viviel
47
58
* @since 2.0.0
48
59
*/
49
60
public class ApplicationConversionService extends FormattingConversionService {
@@ -157,17 +168,30 @@ public static void addApplicationFormatters(FormatterRegistry registry) {
157
168
* @since 2.2.0
158
169
*/
159
170
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 ();
166
178
if (bean instanceof GenericConverter ) {
167
179
registry .addConverter ((GenericConverter ) bean );
168
180
}
169
181
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
+ }
171
195
}
172
196
else if (bean instanceof Formatter ) {
173
197
registry .addFormatter ((Formatter <?>) bean );
@@ -181,4 +205,87 @@ else if (bean instanceof Parser) {
181
205
}
182
206
}
183
207
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
+
184
291
}
0 commit comments