Do not validate value object bean definion when singleton present
Prior to this commit constructor bound configuration properties could not be mocked because it would fail validation from ConfigurationPropertiesBeanDefinitionValidator. The MockitoPostProcessor registers the mocked bean as a singleton and validation can be skipped if a singleton for the type is found in the bean factory. Fixes gh-18652
This commit is contained in:
parent
f9785d2bda
commit
471ca01ccf
|
|
@ -40,13 +40,17 @@ class ConfigurationPropertiesBeanDefinitionValidator implements BeanFactoryPostP
|
|||
@Override
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
for (String beanName : beanFactory.getBeanDefinitionNames()) {
|
||||
BeanDefinition definition = beanFactory.getBeanDefinition(beanName);
|
||||
if (!(definition instanceof ConfigurationPropertiesValueObjectBeanDefinition)) {
|
||||
if (!(beanFactory.containsSingleton(beanName) || isValueObjectBeanDefinition(beanFactory, beanName))) {
|
||||
validate(beanFactory, beanName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isValueObjectBeanDefinition(ConfigurableListableBeanFactory beanFactory, String beanName) {
|
||||
BeanDefinition definition = beanFactory.getBeanDefinition(beanName);
|
||||
return (definition instanceof ConfigurationPropertiesValueObjectBeanDefinition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return Ordered.LOWEST_PRECEDENCE;
|
||||
|
|
|
|||
|
|
@ -44,8 +44,11 @@ import org.springframework.beans.factory.InitializingBean;
|
|||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.GenericBeanDefinition;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.boot.context.properties.bind.BindException;
|
||||
import org.springframework.boot.context.properties.bind.DefaultValue;
|
||||
import org.springframework.boot.context.properties.bind.validation.BindValidationException;
|
||||
|
|
@ -895,6 +898,15 @@ class ConfigurationPropertiesTests {
|
|||
assertThat(bean.getNested().getAge()).isEqualTo(10);
|
||||
}
|
||||
|
||||
@Test // gh-18652
|
||||
void loadWhenBeanFactoryContainsSingletonForConstructorBindingTypeShouldNotFail() {
|
||||
ConfigurableListableBeanFactory beanFactory = this.context.getBeanFactory();
|
||||
((BeanDefinitionRegistry) beanFactory).registerBeanDefinition("test",
|
||||
new RootBeanDefinition(ConstructorParameterProperties.class));
|
||||
beanFactory.registerSingleton("test", new ConstructorParameterProperties("bar", 5));
|
||||
load(TestConfiguration.class);
|
||||
}
|
||||
|
||||
private AnnotationConfigApplicationContext load(Class<?> configuration, String... inlinedProperties) {
|
||||
return load(new Class<?>[] { configuration }, inlinedProperties);
|
||||
}
|
||||
|
|
@ -921,6 +933,12 @@ class ConfigurationPropertiesTests {
|
|||
this.context = new AnnotationConfigApplicationContext();
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableConfigurationProperties
|
||||
static class TestConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableConfigurationProperties(BasicProperties.class)
|
||||
static class BasicConfiguration {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
package org.springframework.boot.context.properties
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext
|
||||
import org.springframework.context.annotation.Configuration
|
||||
|
||||
/**
|
||||
* Tests for {@link ConfigurationProperties @ConfigurationProperties}-annotated beans.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
class KotlinConfigurationPropertiesTests {
|
||||
|
||||
private var context = AnnotationConfigApplicationContext()
|
||||
|
||||
@Test //gh-18652
|
||||
fun `type with constructor binding and existing singleton should not fail`() {
|
||||
val beanFactory = this.context.beanFactory
|
||||
(beanFactory as BeanDefinitionRegistry).registerBeanDefinition("foo",
|
||||
RootBeanDefinition(BingProperties::class.java))
|
||||
beanFactory.registerSingleton("foo", BingProperties(""))
|
||||
this.context.register(TestConfig::class.java)
|
||||
this.context.refresh();
|
||||
}
|
||||
|
||||
@ConfigurationProperties(prefix = "foo")
|
||||
@ConstructorBinding
|
||||
class BingProperties(@Suppress("UNUSED_PARAMETER") bar: String) {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableConfigurationProperties
|
||||
internal open class TestConfig {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue