17
17
package org .springframework .boot .context .properties ;
18
18
19
19
import java .io .IOException ;
20
+ import java .util .Collections ;
20
21
import java .util .Iterator ;
22
+ import java .util .List ;
21
23
import java .util .Map ;
22
24
23
25
import org .springframework .beans .BeansException ;
28
30
import org .springframework .beans .factory .InitializingBean ;
29
31
import org .springframework .beans .factory .ListableBeanFactory ;
30
32
import org .springframework .beans .factory .NoSuchBeanDefinitionException ;
33
+ import org .springframework .beans .factory .annotation .Autowired ;
31
34
import org .springframework .beans .factory .config .BeanPostProcessor ;
32
35
import org .springframework .boot .bind .PropertiesConfigurationFactory ;
33
36
import org .springframework .boot .env .PropertySourcesLoader ;
69
72
* @author Stephane Nicoll
70
73
*/
71
74
public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProcessor ,
72
- BeanFactoryAware , ResourceLoaderAware , EnvironmentAware , ApplicationContextAware ,
73
- InitializingBean , DisposableBean , PriorityOrdered {
75
+ BeanFactoryAware , ResourceLoaderAware , EnvironmentAware , ApplicationContextAware ,
76
+ InitializingBean , DisposableBean , PriorityOrdered {
74
77
75
78
public static final String VALIDATOR_BEAN_NAME = "configurationPropertiesValidator" ;
76
79
77
80
private static final String [] VALIDATOR_CLASSES = { "javax.validation.Validator" ,
78
- "javax.validation.ValidatorFactory" };
81
+ "javax.validation.ValidatorFactory" };
79
82
80
83
private ConfigurationBeanFactoryMetaData beans = new ConfigurationBeanFactoryMetaData ();
81
84
@@ -97,8 +100,21 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc
97
100
98
101
private ApplicationContext applicationContext ;
99
102
103
+ private List <Converter <?, ?>> converters = Collections .emptyList ();
104
+
100
105
private int order = Ordered .HIGHEST_PRECEDENCE + 1 ;
101
106
107
+ /**
108
+ * A list of custom converters (in addition to the defaults) to use when
109
+ * converting properties for binding.
110
+ * @param converters the converters to set
111
+ */
112
+ @ Autowired (required = false )
113
+ @ ConfigurationPropertiesBinding
114
+ public void setConverters (List <Converter <?, ?>> converters ) {
115
+ this .converters = converters ;
116
+ }
117
+
102
118
/**
103
119
* @param order the order to set
104
120
*/
@@ -246,8 +262,8 @@ private <T> T getOptionalBean(String name, Class<T> type) {
246
262
@ Override
247
263
public Object postProcessBeforeInitialization (Object bean , String beanName )
248
264
throws BeansException {
249
- ConfigurationProperties annotation = AnnotationUtils . findAnnotation (
250
- bean .getClass (), ConfigurationProperties .class );
265
+ ConfigurationProperties annotation = AnnotationUtils
266
+ . findAnnotation ( bean .getClass (), ConfigurationProperties .class );
251
267
if (annotation != null || bean instanceof ConfigurationPropertiesHolder ) {
252
268
postProcessBeforeInitialization (bean , beanName , annotation );
253
269
}
@@ -267,29 +283,29 @@ public Object postProcessAfterInitialization(Object bean, String beanName)
267
283
268
284
private void postProcessBeforeInitialization (Object bean , String beanName ,
269
285
ConfigurationProperties annotation ) {
270
- Object target = (bean instanceof ConfigurationPropertiesHolder ? (( ConfigurationPropertiesHolder ) bean )
271
- .getTarget () : bean );
286
+ Object target = (bean instanceof ConfigurationPropertiesHolder
287
+ ? (( ConfigurationPropertiesHolder ) bean ) .getTarget () : bean );
272
288
PropertiesConfigurationFactory <Object > factory = new PropertiesConfigurationFactory <Object >(
273
289
target );
274
290
if (annotation != null && annotation .locations ().length != 0 ) {
275
- factory .setPropertySources (loadPropertySources ( annotation . locations (),
276
- annotation .merge ()));
291
+ factory .setPropertySources (
292
+ loadPropertySources ( annotation . locations (), annotation .merge ()));
277
293
}
278
294
else {
279
295
factory .setPropertySources (this .propertySources );
280
296
}
281
297
factory .setValidator (determineValidator (bean ));
282
298
// If no explicit conversion service is provided we add one so that (at least)
283
299
// comma-separated arrays of convertibles can be bound automatically
284
- factory .setConversionService (this .conversionService == null ? getDefaultConversionService ()
285
- : this .conversionService );
300
+ factory .setConversionService (this .conversionService == null
301
+ ? getDefaultConversionService () : this .conversionService );
286
302
if (annotation != null ) {
287
303
factory .setIgnoreInvalidFields (annotation .ignoreInvalidFields ());
288
304
factory .setIgnoreUnknownFields (annotation .ignoreUnknownFields ());
289
305
factory .setExceptionIfInvalid (annotation .exceptionIfInvalid ());
290
306
factory .setIgnoreNestedProperties (annotation .ignoreNestedProperties ());
291
- String targetName = (StringUtils .hasLength (annotation .value ()) ? annotation
292
- .value () : annotation .prefix ());
307
+ String targetName = (StringUtils .hasLength (annotation .value ())
308
+ ? annotation .value () : annotation .prefix ());
293
309
if (StringUtils .hasLength (targetName )) {
294
310
factory .setTargetName (targetName );
295
311
}
@@ -300,7 +316,8 @@ private void postProcessBeforeInitialization(Object bean, String beanName,
300
316
catch (Exception ex ) {
301
317
String targetClass = ClassUtils .getShortName (target .getClass ());
302
318
throw new BeanCreationException (beanName , "Could not bind properties to "
303
- + targetClass + " (" + getAnnotationDetails (annotation ) + ")" , ex );
319
+ + targetClass + " (" + getAnnotationDetails (annotation ) + ")" ,
320
+ ex );
304
321
}
305
322
}
306
323
@@ -309,19 +326,18 @@ private String getAnnotationDetails(ConfigurationProperties annotation) {
309
326
return "" ;
310
327
}
311
328
StringBuilder details = new StringBuilder ();
312
- details .append ("prefix=" ).append (
313
- (StringUtils .hasLength (annotation .value ()) ? annotation .value ()
314
- : annotation .prefix ()));
329
+ details .append ("prefix=" ).append ((StringUtils .hasLength (annotation .value ())
330
+ ? annotation .value () : annotation .prefix ()));
315
331
details .append (", ignoreInvalidFields=" ).append (annotation .ignoreInvalidFields ());
316
332
details .append (", ignoreUnknownFields=" ).append (annotation .ignoreUnknownFields ());
317
- details .append (", ignoreNestedProperties=" ). append (
318
- annotation .ignoreNestedProperties ());
333
+ details .append (", ignoreNestedProperties=" )
334
+ . append ( annotation .ignoreNestedProperties ());
319
335
return details .toString ();
320
336
}
321
337
322
338
private Validator determineValidator (Object bean ) {
323
- boolean globalValidatorSupportBean = (this .validator != null && this . validator
324
- .supports (bean .getClass ()));
339
+ boolean globalValidatorSupportBean = (this .validator != null
340
+ && this . validator .supports (bean .getClass ()));
325
341
if (ClassUtils .isAssignable (Validator .class , bean .getClass ())) {
326
342
if (!globalValidatorSupportBean ) {
327
343
return (Validator ) bean ;
@@ -336,8 +352,8 @@ private PropertySources loadPropertySources(String[] locations,
336
352
try {
337
353
PropertySourcesLoader loader = new PropertySourcesLoader ();
338
354
for (String location : locations ) {
339
- Resource resource = this .resourceLoader . getResource ( this . environment
340
- .resolvePlaceholders (location ));
355
+ Resource resource = this .resourceLoader
356
+ .getResource ( this . environment . resolvePlaceholders (location ));
341
357
String [] profiles = this .environment .getActiveProfiles ();
342
358
for (int i = profiles .length ; i -- > 0 ;) {
343
359
String profile = profiles [i ];
@@ -361,8 +377,9 @@ private PropertySources loadPropertySources(String[] locations,
361
377
private ConversionService getDefaultConversionService () {
362
378
if (this .defaultConversionService == null ) {
363
379
DefaultConversionService conversionService = new DefaultConversionService ();
364
- for (Converter <?, ?> converter : ((ListableBeanFactory ) this .beanFactory )
365
- .getBeansOfType (Converter .class , false , false ).values ()) {
380
+ this .applicationContext .getAutowireCapableBeanFactory ()
381
+ .autowireBean (this );
382
+ for (Converter <?, ?> converter : this .converters ) {
366
383
conversionService .addConverter (converter );
367
384
}
368
385
this .defaultConversionService = conversionService ;
@@ -371,8 +388,8 @@ private ConversionService getDefaultConversionService() {
371
388
}
372
389
373
390
/**
374
- * Factory to create JSR 303 LocalValidatorFactoryBean. Inner class to prevent class
375
- * loader issues.
391
+ * Factory to create JSR 303 LocalValidatorFactoryBean. Inner class to prevent
392
+ * class loader issues.
376
393
*/
377
394
private static class Jsr303ValidatorFactory {
378
395
@@ -386,8 +403,8 @@ public Validator run(ApplicationContext applicationContext) {
386
403
}
387
404
388
405
/**
389
- * {@link Validator} implementation that wraps {@link Validator} instances and chains
390
- * their execution.
406
+ * {@link Validator} implementation that wraps {@link Validator} instances and
407
+ * chains their execution.
391
408
*/
392
409
private static class ChainingValidator implements Validator {
393
410
@@ -421,7 +438,8 @@ public void validate(Object target, Errors errors) {
421
438
422
439
/**
423
440
* Convenience class to flatten out a tree of property sources without losing the
424
- * reference to the backing data (which can therefore be updated in the background).
441
+ * reference to the backing data (which can therefore be updated in the
442
+ * background).
425
443
*/
426
444
private static class FlatPropertySources implements PropertySources {
427
445
0 commit comments