@ -16,14 +16,18 @@
package org.springframework.boot.context.properties ;
package org.springframework.boot.context.properties ;
import java.lang.reflect.Constructor ;
import java.util.ArrayList ;
import java.util.ArrayList ;
import java.util.List ;
import java.util.List ;
import org.springframework.aot.generate.GenerationContext ;
import org.springframework.aot.generate.GenerationContext ;
import org.springframework.beans.BeansException ;
import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution ;
import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution ;
import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor ;
import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor ;
import org.springframework.beans.factory.aot.BeanFactoryInitializationCode ;
import org.springframework.beans.factory.aot.BeanFactoryInitializationCode ;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory ;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory ;
import org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor ;
import org.springframework.boot.context.properties.bind.BindConstructorProvider ;
import org.springframework.boot.context.properties.bind.BindMethod ;
import org.springframework.boot.context.properties.bind.BindMethod ;
import org.springframework.boot.context.properties.bind.Bindable ;
import org.springframework.boot.context.properties.bind.Bindable ;
import org.springframework.boot.context.properties.bind.BindableRuntimeHintsRegistrar ;
import org.springframework.boot.context.properties.bind.BindableRuntimeHintsRegistrar ;
@ -43,6 +47,7 @@ class ConfigurationPropertiesBeanFactoryInitializationAotProcessor implements Be
@Override
@Override
public ConfigurationPropertiesReflectionHintsContribution processAheadOfTime (
public ConfigurationPropertiesReflectionHintsContribution processAheadOfTime (
ConfigurableListableBeanFactory beanFactory ) {
ConfigurableListableBeanFactory beanFactory ) {
beanFactory . addBeanPostProcessor ( new BindConstructorAwareBeanPostProcessor ( beanFactory ) ) ;
String [ ] beanNames = beanFactory . getBeanNamesForAnnotation ( ConfigurationProperties . class ) ;
String [ ] beanNames = beanFactory . getBeanNamesForAnnotation ( ConfigurationProperties . class ) ;
List < Bindable < ? > > bindables = new ArrayList < > ( ) ;
List < Bindable < ? > > bindables = new ArrayList < > ( ) ;
for ( String beanName : beanNames ) {
for ( String beanName : beanNames ) {
@ -58,6 +63,37 @@ class ConfigurationPropertiesBeanFactoryInitializationAotProcessor implements Be
return ( ! bindables . isEmpty ( ) ) ? new ConfigurationPropertiesReflectionHintsContribution ( bindables ) : null ;
return ( ! bindables . isEmpty ( ) ) ? new ConfigurationPropertiesReflectionHintsContribution ( bindables ) : null ;
}
}
/ * *
* { @link SmartInstantiationAwareBeanPostProcessor } implementation to work around
* framework ' s constructor resolver for immutable configuration properties .
* < p >
* Constructor binding supports multiple constructors as long as one is identified as
* the candidate for binding . Unfortunately , framework is not aware of such feature
* and attempts to resolve the autowired constructor to use .
* /
static class BindConstructorAwareBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {
private final ConfigurableListableBeanFactory beanFactory ;
BindConstructorAwareBeanPostProcessor ( ConfigurableListableBeanFactory beanFactory ) {
this . beanFactory = beanFactory ;
}
@Override
public Constructor < ? > [ ] determineCandidateConstructors ( Class < ? > beanClass , String beanName )
throws BeansException {
BindMethod bindMethod = BindMethodAttribute . get ( this . beanFactory , beanName ) ;
if ( bindMethod ! = null & & bindMethod = = BindMethod . VALUE_OBJECT ) {
Constructor < ? > bindConstructor = BindConstructorProvider . DEFAULT . getBindConstructor ( beanClass , false ) ;
if ( bindConstructor ! = null ) {
return new Constructor < ? > [ ] { bindConstructor } ;
}
}
return null ;
}
}
static final class ConfigurationPropertiesReflectionHintsContribution
static final class ConfigurationPropertiesReflectionHintsContribution
implements BeanFactoryInitializationAotContribution {
implements BeanFactoryInitializationAotContribution {