ConfigurationPropertiesBinder Class — spring-boot Architecture
Architecture documentation for the ConfigurationPropertiesBinder class in ConfigurationPropertiesBinder.java from the spring-boot codebase.
Entity Profile
Relationship Graph
Source Code
core/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBinder.java lines 67–300
class ConfigurationPropertiesBinder {
private static final String BEAN_NAME = "org.springframework.boot.context.internalConfigurationPropertiesBinder";
private static final String VALIDATOR_BEAN_NAME = EnableConfigurationProperties.VALIDATOR_BEAN_NAME;
private final ApplicationContext applicationContext;
private final PropertySources propertySources;
private final @Nullable Validator configurationPropertiesValidator;
private final boolean jsr303Present;
private volatile @Nullable List<ConfigurationPropertiesBindHandlerAdvisor> bindHandlerAdvisors;
private volatile @Nullable Binder binder;
ConfigurationPropertiesBinder(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
this.propertySources = new PropertySourcesDeducer(applicationContext).getPropertySources();
this.configurationPropertiesValidator = getConfigurationPropertiesValidator(applicationContext);
this.jsr303Present = ConfigurationPropertiesJsr303Validator.isJsr303Present(applicationContext);
}
BindResult<?> bind(ConfigurationPropertiesBean propertiesBean) {
Bindable<?> target = propertiesBean.asBindTarget();
ConfigurationProperties annotation = propertiesBean.getAnnotation();
BindHandler bindHandler = getBindHandler(target, annotation);
return getBinder().bind(annotation.prefix(), target, bindHandler);
}
Object bindOrCreate(ConfigurationPropertiesBean propertiesBean) {
Bindable<?> target = propertiesBean.asBindTarget();
ConfigurationProperties annotation = propertiesBean.getAnnotation();
BindHandler bindHandler = getBindHandler(target, annotation);
return getBinder().bindOrCreate(annotation.prefix(), target, bindHandler);
}
private @Nullable Validator getConfigurationPropertiesValidator(ApplicationContext applicationContext) {
if (applicationContext.containsBean(VALIDATOR_BEAN_NAME)) {
return applicationContext.getBean(VALIDATOR_BEAN_NAME, Validator.class);
}
return null;
}
private <T> BindHandler getBindHandler(Bindable<T> target, ConfigurationProperties annotation) {
List<Validator> validators = getValidators(target);
BindHandler handler = getHandler();
handler = new ConfigurationPropertiesBindHandler(handler);
if (annotation.ignoreInvalidFields()) {
handler = new IgnoreErrorsBindHandler(handler);
}
if (!annotation.ignoreUnknownFields()) {
UnboundElementsSourceFilter filter = new UnboundElementsSourceFilter();
handler = new NoUnboundElementsBindHandler(handler, filter);
}
if (!validators.isEmpty()) {
handler = new ValidationBindHandler(handler, validators.toArray(new Validator[0]));
}
for (ConfigurationPropertiesBindHandlerAdvisor advisor : getBindHandlerAdvisors()) {
handler = advisor.apply(handler);
}
return handler;
}
private List<ConfigurationPropertiesBindHandlerAdvisor> getBindHandlerAdvisors() {
List<ConfigurationPropertiesBindHandlerAdvisor> bindHandlerAdvisors = this.bindHandlerAdvisors;
if (bindHandlerAdvisors == null) {
bindHandlerAdvisors = this.applicationContext
.getBeanProvider(ConfigurationPropertiesBindHandlerAdvisor.class)
.orderedStream()
.toList();
this.bindHandlerAdvisors = bindHandlerAdvisors;
}
return bindHandlerAdvisors;
}
private IgnoreTopLevelConverterNotFoundBindHandler getHandler() {
BoundConfigurationProperties bound = BoundConfigurationProperties.get(this.applicationContext);
return (bound != null)
? new IgnoreTopLevelConverterNotFoundBindHandler(new BoundPropertiesTrackingBindHandler(bound::add))
: new IgnoreTopLevelConverterNotFoundBindHandler();
}
private List<Validator> getValidators(Bindable<?> target) {
List<Validator> validators = new ArrayList<>(3);
if (this.configurationPropertiesValidator != null) {
validators.add(this.configurationPropertiesValidator);
}
if (this.jsr303Present && target.getAnnotation(Validated.class) != null) {
Class<?> resolved = target.getType().resolve();
Assert.state(resolved != null, "'resolved' must not be null");
validators.add(getJsr303Validator(resolved));
}
Validator selfValidator = getSelfValidator(target);
if (selfValidator != null) {
validators.add(selfValidator);
}
return validators;
}
private @Nullable Validator getSelfValidator(Bindable<?> target) {
if (target.getValue() != null) {
Object value = target.getValue().get();
return (value instanceof Validator validator) ? validator : null;
}
Class<?> type = target.getType().resolve();
if (type != null && Validator.class.isAssignableFrom(type)) {
return new SelfValidatingConstructorBoundBindableValidator(type);
}
return null;
}
private Validator getJsr303Validator(Class<?> type) {
return new ConfigurationPropertiesJsr303Validator(this.applicationContext, type);
}
private Binder getBinder() {
Binder binder = this.binder;
if (binder == null) {
binder = new Binder(getConfigurationPropertySources(), getPropertySourcesPlaceholdersResolver(),
getConversionServices(), getPropertyEditorInitializer(), null, null);
this.binder = binder;
}
return binder;
}
private Iterable<ConfigurationPropertySource> getConfigurationPropertySources() {
return ConfigurationPropertySources.from(this.propertySources);
}
private PropertySourcesPlaceholdersResolver getPropertySourcesPlaceholdersResolver() {
return new PropertySourcesPlaceholdersResolver(this.propertySources);
}
private @Nullable List<ConversionService> getConversionServices() {
return new ConversionServiceDeducer(this.applicationContext).getConversionServices();
}
private @Nullable Consumer<PropertyEditorRegistry> getPropertyEditorInitializer() {
if (this.applicationContext instanceof ConfigurableApplicationContext configurableContext) {
return configurableContext.getBeanFactory()::copyRegisteredEditorsTo;
}
return null;
}
static void register(BeanDefinitionRegistry registry) {
if (!registry.containsBeanDefinition(BEAN_NAME)) {
BeanDefinition definition = BeanDefinitionBuilder
.rootBeanDefinition(ConfigurationPropertiesBinderFactory.class)
.getBeanDefinition();
definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(BEAN_NAME, definition);
}
}
static ConfigurationPropertiesBinder get(BeanFactory beanFactory) {
return beanFactory.getBean(BEAN_NAME, ConfigurationPropertiesBinder.class);
}
/**
* {@link BindHandler} to deal with
* {@link ConfigurationProperties @ConfigurationProperties} concerns.
*/
private static class ConfigurationPropertiesBindHandler extends AbstractBindHandler {
ConfigurationPropertiesBindHandler(BindHandler handler) {
super(handler);
}
@Override
public <T> Bindable<T> onStart(ConfigurationPropertyName name, Bindable<T> target, BindContext context) {
return isConfigurationProperties(target.getType().resolve())
? target.withBindRestrictions(BindRestriction.NO_DIRECT_PROPERTY) : target;
}
private boolean isConfigurationProperties(@Nullable Class<?> target) {
return target != null && MergedAnnotations.from(target).isPresent(ConfigurationProperties.class);
}
}
/**
* {@link FactoryBean} to create the {@link ConfigurationPropertiesBinder}.
*/
static class ConfigurationPropertiesBinderFactory
implements FactoryBean<ConfigurationPropertiesBinder>, ApplicationContextAware {
private @Nullable ConfigurationPropertiesBinder binder;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.binder = (this.binder != null) ? this.binder : new ConfigurationPropertiesBinder(applicationContext);
}
@Override
public Class<?> getObjectType() {
return ConfigurationPropertiesBinder.class;
}
@Override
public ConfigurationPropertiesBinder getObject() throws Exception {
Assert.state(this.binder != null, "Binder was not created due to missing setApplicationContext call");
return this.binder;
}
}
/**
* A {@code Validator} for a constructor-bound {@code Bindable} where the type being
* bound is itself a {@code Validator} implementation.
*/
static class SelfValidatingConstructorBoundBindableValidator implements Validator {
private final Class<?> type;
SelfValidatingConstructorBoundBindableValidator(Class<?> type) {
this.type = type;
}
@Override
public boolean supports(Class<?> candidate) {
return candidate.isAssignableFrom(this.type);
}
@Override
public void validate(Object target, Errors errors) {
((Validator) target).validate(target, errors);
}
}
}
Domain
Source
Analyze Your Own Codebase
Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.
Try Supermodel Free