1717package org .springframework .boot .context .properties ;
1818
1919import java .io .IOException ;
20+ import java .util .Collections ;
2021import java .util .Iterator ;
22+ import java .util .List ;
2123import java .util .Map ;
2224
2325import org .springframework .beans .BeansException ;
2830import org .springframework .beans .factory .InitializingBean ;
2931import org .springframework .beans .factory .ListableBeanFactory ;
3032import org .springframework .beans .factory .NoSuchBeanDefinitionException ;
33+ import org .springframework .beans .factory .annotation .Autowired ;
3134import org .springframework .beans .factory .config .BeanPostProcessor ;
3235import org .springframework .boot .bind .PropertiesConfigurationFactory ;
3336import org .springframework .boot .env .PropertySourcesLoader ;
6972 * @author Stephane Nicoll
7073 */
7174public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProcessor ,
72- BeanFactoryAware , ResourceLoaderAware , EnvironmentAware , ApplicationContextAware ,
73- InitializingBean , DisposableBean , PriorityOrdered {
75+ BeanFactoryAware , ResourceLoaderAware , EnvironmentAware , ApplicationContextAware ,
76+ InitializingBean , DisposableBean , PriorityOrdered {
7477
7578 public static final String VALIDATOR_BEAN_NAME = "configurationPropertiesValidator" ;
7679
7780 private static final String [] VALIDATOR_CLASSES = { "javax.validation.Validator" ,
78- "javax.validation.ValidatorFactory" };
81+ "javax.validation.ValidatorFactory" };
7982
8083 private ConfigurationBeanFactoryMetaData beans = new ConfigurationBeanFactoryMetaData ();
8184
@@ -97,8 +100,21 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc
97100
98101 private ApplicationContext applicationContext ;
99102
103+ private List <Converter <?, ?>> converters = Collections .emptyList ();
104+
100105 private int order = Ordered .HIGHEST_PRECEDENCE + 1 ;
101106
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+
102118 /**
103119 * @param order the order to set
104120 */
@@ -246,8 +262,8 @@ private <T> T getOptionalBean(String name, Class<T> type) {
246262 @ Override
247263 public Object postProcessBeforeInitialization (Object bean , String beanName )
248264 throws BeansException {
249- ConfigurationProperties annotation = AnnotationUtils . findAnnotation (
250- bean .getClass (), ConfigurationProperties .class );
265+ ConfigurationProperties annotation = AnnotationUtils
266+ . findAnnotation ( bean .getClass (), ConfigurationProperties .class );
251267 if (annotation != null || bean instanceof ConfigurationPropertiesHolder ) {
252268 postProcessBeforeInitialization (bean , beanName , annotation );
253269 }
@@ -267,29 +283,29 @@ public Object postProcessAfterInitialization(Object bean, String beanName)
267283
268284 private void postProcessBeforeInitialization (Object bean , String beanName ,
269285 ConfigurationProperties annotation ) {
270- Object target = (bean instanceof ConfigurationPropertiesHolder ? (( ConfigurationPropertiesHolder ) bean )
271- .getTarget () : bean );
286+ Object target = (bean instanceof ConfigurationPropertiesHolder
287+ ? (( ConfigurationPropertiesHolder ) bean ) .getTarget () : bean );
272288 PropertiesConfigurationFactory <Object > factory = new PropertiesConfigurationFactory <Object >(
273289 target );
274290 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 ()));
277293 }
278294 else {
279295 factory .setPropertySources (this .propertySources );
280296 }
281297 factory .setValidator (determineValidator (bean ));
282298 // If no explicit conversion service is provided we add one so that (at least)
283299 // 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 );
286302 if (annotation != null ) {
287303 factory .setIgnoreInvalidFields (annotation .ignoreInvalidFields ());
288304 factory .setIgnoreUnknownFields (annotation .ignoreUnknownFields ());
289305 factory .setExceptionIfInvalid (annotation .exceptionIfInvalid ());
290306 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 ());
293309 if (StringUtils .hasLength (targetName )) {
294310 factory .setTargetName (targetName );
295311 }
@@ -300,7 +316,8 @@ private void postProcessBeforeInitialization(Object bean, String beanName,
300316 catch (Exception ex ) {
301317 String targetClass = ClassUtils .getShortName (target .getClass ());
302318 throw new BeanCreationException (beanName , "Could not bind properties to "
303- + targetClass + " (" + getAnnotationDetails (annotation ) + ")" , ex );
319+ + targetClass + " (" + getAnnotationDetails (annotation ) + ")" ,
320+ ex );
304321 }
305322 }
306323
@@ -309,19 +326,18 @@ private String getAnnotationDetails(ConfigurationProperties annotation) {
309326 return "" ;
310327 }
311328 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 ()));
315331 details .append (", ignoreInvalidFields=" ).append (annotation .ignoreInvalidFields ());
316332 details .append (", ignoreUnknownFields=" ).append (annotation .ignoreUnknownFields ());
317- details .append (", ignoreNestedProperties=" ). append (
318- annotation .ignoreNestedProperties ());
333+ details .append (", ignoreNestedProperties=" )
334+ . append ( annotation .ignoreNestedProperties ());
319335 return details .toString ();
320336 }
321337
322338 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 ()));
325341 if (ClassUtils .isAssignable (Validator .class , bean .getClass ())) {
326342 if (!globalValidatorSupportBean ) {
327343 return (Validator ) bean ;
@@ -336,8 +352,8 @@ private PropertySources loadPropertySources(String[] locations,
336352 try {
337353 PropertySourcesLoader loader = new PropertySourcesLoader ();
338354 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 ));
341357 String [] profiles = this .environment .getActiveProfiles ();
342358 for (int i = profiles .length ; i -- > 0 ;) {
343359 String profile = profiles [i ];
@@ -361,8 +377,9 @@ private PropertySources loadPropertySources(String[] locations,
361377 private ConversionService getDefaultConversionService () {
362378 if (this .defaultConversionService == null ) {
363379 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 ) {
366383 conversionService .addConverter (converter );
367384 }
368385 this .defaultConversionService = conversionService ;
@@ -371,8 +388,8 @@ private ConversionService getDefaultConversionService() {
371388 }
372389
373390 /**
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.
376393 */
377394 private static class Jsr303ValidatorFactory {
378395
@@ -386,8 +403,8 @@ public Validator run(ApplicationContext applicationContext) {
386403 }
387404
388405 /**
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.
391408 */
392409 private static class ChainingValidator implements Validator {
393410
@@ -421,7 +438,8 @@ public void validate(Object target, Errors errors) {
421438
422439 /**
423440 * 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).
425443 */
426444 private static class FlatPropertySources implements PropertySources {
427445
0 commit comments