ConfigurationPropertiesTests Class — spring-boot Architecture
Architecture documentation for the ConfigurationPropertiesTests class in ConfigurationPropertiesTests.java from the spring-boot codebase.
Entity Profile
Relationship Graph
Source Code
core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesTests.java lines 136–3380
@ExtendWith(OutputCaptureExtension.class)
class ConfigurationPropertiesTests {
private AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
@AfterEach
void cleanup() {
this.context.close();
System.clearProperty("name");
System.clearProperty("nested.name");
System.clearProperty("nested_name");
}
@Test
void loadShouldBind() {
load(BasicConfiguration.class, "name=foo");
assertThat(this.context.getBeanNamesForType(BasicProperties.class)).hasSize(1);
assertThat(this.context.containsBean(BasicProperties.class.getName())).isTrue();
assertThat(this.context.getBean(BasicProperties.class).name).isEqualTo("foo");
}
@Test
void loadShouldBindNested() {
load(NestedConfiguration.class, "name=foo", "nested.name=bar");
assertThat(this.context.getBeanNamesForType(NestedProperties.class)).hasSize(1);
assertThat(this.context.getBean(NestedProperties.class).name).isEqualTo("foo");
assertThat(this.context.getBean(NestedProperties.class).nested.name).isEqualTo("bar");
}
@Test
void loadWhenUsingSystemPropertiesShouldBind() {
System.setProperty("name", "foo");
load(BasicConfiguration.class);
assertThat(this.context.getBeanNamesForType(BasicProperties.class)).hasSize(1);
assertThat(this.context.getBean(BasicProperties.class).name).isEqualTo("foo");
}
@Test
void loadWhenUsingSystemPropertiesShouldBindNested() {
System.setProperty("name", "foo");
System.setProperty("nested.name", "bar");
load(NestedConfiguration.class);
assertThat(this.context.getBeanNamesForType(NestedProperties.class)).hasSize(1);
assertThat(this.context.getBean(NestedProperties.class).name).isEqualTo("foo");
assertThat(this.context.getBean(NestedProperties.class).nested.name).isEqualTo("bar");
}
@Test
void loadWhenHasIgnoreUnknownFieldsFalseAndNoUnknownFieldsShouldBind() {
removeSystemProperties();
load(IgnoreUnknownFieldsFalseConfiguration.class, "name=foo");
IgnoreUnknownFieldsFalseProperties bean = this.context.getBean(IgnoreUnknownFieldsFalseProperties.class);
assertThat(((BasicProperties) bean).name).isEqualTo("foo");
}
@Test
void loadWhenHasIgnoreUnknownFieldsFalseAndUnknownFieldsShouldFail() {
removeSystemProperties();
assertThatExceptionOfType(ConfigurationPropertiesBindException.class)
.isThrownBy(() -> load(IgnoreUnknownFieldsFalseConfiguration.class, "name=foo", "bar=baz"))
.withCauseInstanceOf(BindException.class);
}
@Test
void givenIgnoreUnknownFieldsFalseAndIgnoreInvalidFieldsTrueWhenThereAreUnknownFieldsThenBindingShouldFail() {
removeSystemProperties();
assertThatExceptionOfType(ConfigurationPropertiesBindException.class).isThrownBy(
() -> load(IgnoreUnknownFieldsFalseIgnoreInvalidFieldsTrueConfiguration.class, "name=foo", "bar=baz"))
.withCauseInstanceOf(BindException.class);
}
@Test
void loadWhenHasIgnoreInvalidFieldsTrueAndInvalidFieldsShouldBind() {
load(IgnoreInvalidFieldsFalseProperties.class, "com.example.bar=spam");
IgnoreInvalidFieldsFalseProperties bean = this.context.getBean(IgnoreInvalidFieldsFalseProperties.class);
assertThat(bean.getBar()).isZero();
}
@Test
void loadWhenHasPrefixShouldBind() {
load(PrefixConfiguration.class, "spring.foo.name=foo");
PrefixProperties bean = this.context.getBean(PrefixProperties.class);
assertThat(((BasicProperties) bean).name).isEqualTo("foo");
}
@Test
void loadWhenPropertiesHaveAnnotationOnBaseClassShouldBind() {
load(AnnotationOnBaseClassConfiguration.class, "name=foo");
AnnotationOnBaseClassProperties bean = this.context.getBean(AnnotationOnBaseClassProperties.class);
assertThat(((BasicProperties) bean).name).isEqualTo("foo");
}
@Test
void loadWhenBindingArrayShouldBind() {
load(BasicConfiguration.class, "name=foo", "array=1,2,3");
BasicProperties bean = this.context.getBean(BasicProperties.class);
assertThat(bean.array).containsExactly(1, 2, 3);
}
@Test
void loadWhenBindingArrayFromYamlArrayShouldBind() {
load(BasicConfiguration.class, "name=foo", "list[0]=1", "list[1]=2", "list[2]=3");
BasicProperties bean = this.context.getBean(BasicProperties.class);
assertThat(bean.list).containsExactly(1, 2, 3);
}
@Test
void loadWhenBindingOver256ElementsShouldBind() {
List<String> pairs = new ArrayList<>();
pairs.add("name:foo");
for (int i = 0; i < 1000; i++) {
pairs.add("list[" + i + "]:" + i);
}
load(BasicConfiguration.class, StringUtils.toStringArray(pairs));
BasicProperties bean = this.context.getBean(BasicProperties.class);
assertThat(bean.list).hasSize(1000);
}
@Test
void loadWhenBindingWithoutAndAnnotationShouldFail() {
assertThatIllegalStateException().isThrownBy(() -> load(WithoutAndAnnotationConfiguration.class, "name:foo"))
.withMessageContaining("No ConfigurationProperties annotation found");
}
@Test
void loadWhenBindingWithoutAnnotationValueShouldBind() {
load(WithoutAnnotationValueConfiguration.class, "name=foo");
WithoutAnnotationValueProperties bean = this.context.getBean(WithoutAnnotationValueProperties.class);
assertThat(bean.name).isEqualTo("foo");
}
@Test
@WithResource(name = "testProperties.xml",
content = """
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean
id="org.springframework.boot.context.properties.ConfigurationPropertiesTests$BasicProperties"
class="org.springframework.boot.context.properties.ConfigurationPropertiesTests$BasicProperties">
<property name="name" value="bar"/>
</bean>
</beans>
""")
void loadWhenBindingWithDefaultsInXmlShouldBind() {
removeSystemProperties();
load(new Class<?>[] { DefaultsInXmlConfiguration.class });
BasicProperties bean = this.context.getBean(BasicProperties.class);
assertThat(bean.name).isEqualTo("bar");
}
@Test
void loadWhenBindingWithDefaultsInJavaConfigurationShouldBind() {
load(DefaultsInJavaConfiguration.class);
BasicProperties bean = this.context.getBean(BasicProperties.class);
assertThat(bean.name).isEqualTo("bar");
}
@Test
void loadWhenBindingTwoBeansShouldBind() {
load(new Class<?>[] { WithoutAnnotationValueConfiguration.class, BasicConfiguration.class });
assertThat(this.context.getBean(BasicProperties.class)).isNotNull();
assertThat(this.context.getBean(WithoutAnnotationValueProperties.class)).isNotNull();
}
@Test
void loadWhenBindingWithParentContextShouldBind() {
AnnotationConfigApplicationContext parent = load(BasicConfiguration.class, "name=parent");
assertThat(parent.getEnvironment().getProperty("name")).isEqualTo("parent");
this.context = new AnnotationConfigApplicationContext();
this.context.setParent(parent);
removeSystemProperties();
load(new Class<?>[] { BasicConfiguration.class, BasicPropertiesConsumer.class }, "name=child");
assertThat(this.context.getEnvironment().getProperty("name")).isEqualTo("child");
assertThat(this.context.getBean(BasicProperties.class)).isNotNull();
assertThat(parent.getBean(BasicProperties.class)).isNotNull();
assertThat(this.context.getBean(BasicPropertiesConsumer.class).getName()).isEqualTo("child");
parent.close();
}
@Test
void loadWhenBindingOnlyParentContextShouldBind() {
AnnotationConfigApplicationContext parent = load(BasicConfiguration.class, "name=foo");
this.context = new AnnotationConfigApplicationContext();
this.context.setParent(parent);
load(BasicPropertiesConsumer.class);
assertThat(this.context.getBeanNamesForType(BasicProperties.class)).isEmpty();
assertThat(parent.getBeanNamesForType(BasicProperties.class)).hasSize(1);
assertThat(this.context.getBean(BasicPropertiesConsumer.class).getName()).isEqualTo("foo");
}
@Test
void loadWhenPrefixedPropertiesDeclaredAsBeanShouldBind() {
load(PrefixPropertiesDeclaredAsBeanConfiguration.class, "spring.foo.name=foo");
PrefixProperties bean = this.context.getBean(PrefixProperties.class);
assertThat(((BasicProperties) bean).name).isEqualTo("foo");
}
@Test
void loadWhenPrefixedPropertiesDeclaredAsAnnotationValueShouldBind() {
load(PrefixPropertiesDeclaredAsAnnotationValueConfiguration.class, "spring.foo.name=foo");
PrefixProperties bean = this.context.getBean("spring.foo-" + PrefixProperties.class.getName(),
PrefixProperties.class);
assertThat(((BasicProperties) bean).name).isEqualTo("foo");
}
@Test
void loadWhenMultiplePrefixedPropertiesDeclaredAsAnnotationValueShouldBind() {
load(MultiplePrefixPropertiesDeclaredAsAnnotationValueConfiguration.class, "spring.foo.name=foo",
"spring.bar.name=bar");
PrefixProperties bean1 = this.context.getBean(PrefixProperties.class);
AnotherPrefixProperties bean2 = this.context.getBean(AnotherPrefixProperties.class);
assertThat(((BasicProperties) bean1).name).isEqualTo("foo");
assertThat(((BasicProperties) bean2).name).isEqualTo("bar");
}
@Test
void loadWhenBindingToMapKeyWithPeriodShouldBind() {
load(MapProperties.class, "mymap.key1.key2:value12", "mymap.key3:value3");
MapProperties bean = this.context.getBean(MapProperties.class);
assertThat(bean.mymap).containsOnly(entry("key3", "value3"), entry("key1.key2", "value12"));
}
@Test
void loadWhenPrefixedPropertiesAreReplacedOnBeanMethodShouldBind() {
load(PrefixedPropertiesReplacedOnBeanMethodConfiguration.class, "external.name=bar", "spam.name=foo");
PrefixProperties bean = this.context.getBean(PrefixProperties.class);
assertThat(((BasicProperties) bean).name).isEqualTo("foo");
}
@Test
void loadShouldBindToJavaTimeDuration() {
load(BasicConfiguration.class, "duration=PT1M");
BasicProperties bean = this.context.getBean(BasicProperties.class);
Duration duration = bean.getDuration();
assertThat(duration).isNotNull();
assertThat(duration.getSeconds()).isEqualTo(60);
}
@Test
void loadWhenBindingToValidatedImplementationOfInterfaceShouldBind() {
load(ValidatedImplementationConfiguration.class, "test.foo=bar");
ValidatedImplementationProperties bean = this.context.getBean(ValidatedImplementationProperties.class);
assertThat(bean.getFoo()).isEqualTo("bar");
}
@Test
void loadWithPropertyPlaceholderValueShouldBind() {
load(WithPropertyPlaceholderValueConfiguration.class, "default.value=foo");
WithPropertyPlaceholderValueProperties bean = this.context
.getBean(WithPropertyPlaceholderValueProperties.class);
assertThat(bean.getValue()).isEqualTo("foo");
}
@Test
void loadWithPropertyPlaceholderShouldNotAlterPropertySourceOrder() {
load(WithPropertyPlaceholderWithLocalPropertiesValueConfiguration.class, "com.example.bar=a");
SimplePrefixedProperties bean = this.context.getBean(SimplePrefixedProperties.class);
assertThat(bean.getBar()).isEqualTo("a");
}
@Test
void loadWhenHasPostConstructShouldTriggerPostConstructWithBoundBean() {
MockEnvironment environment = new MockEnvironment();
environment.setProperty("bar", "foo");
this.context.setEnvironment(environment);
this.context.register(WithPostConstructConfiguration.class);
this.context.refresh();
WithPostConstructConfiguration bean = this.context.getBean(WithPostConstructConfiguration.class);
assertThat(bean.initialized).isTrue();
}
@Test
void loadShouldNotInitializeFactoryBeans() {
WithFactoryBeanConfiguration.factoryBeanInitialized = false;
this.context = new AnnotationConfigApplicationContext() {
@Override
protected void onRefresh() {
assertThat(WithFactoryBeanConfiguration.factoryBeanInitialized).as("Initialized too early").isFalse();
super.onRefresh();
}
};
this.context.register(WithFactoryBeanConfiguration.class);
BeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(FactoryBeanTester.class)
.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE)
.getBeanDefinition();
this.context.registerBeanDefinition("test", beanDefinition);
this.context.refresh();
assertThat(WithFactoryBeanConfiguration.factoryBeanInitialized).as("Not Initialized").isTrue();
}
@Test
void loadWhenUsingRelaxedFormsShouldBindToEnum() {
bindToEnum("test.theValue=FOO");
bindToEnum("test.theValue=foo");
bindToEnum("test.the-value=FoO");
bindToEnum("test.THE_VALUE=FoO");
}
private void bindToEnum(String... inlinedProperties) {
load(WithEnumProperties.class, inlinedProperties);
WithEnumProperties bean = this.context.getBean(WithEnumProperties.class);
assertThat(bean.getTheValue()).isEqualTo(FooEnum.FOO);
resetContext();
}
@Test
void loadWhenUsingRelaxedFormsShouldBindToEnumSet() {
bindToEnumSet("test.the-values=foo,bar", FooEnum.FOO, FooEnum.BAR);
bindToEnumSet("test.the-values=foo", FooEnum.FOO);
}
private void bindToEnumSet(String inlinedProperty, FooEnum... expected) {
load(WithEnumProperties.class, inlinedProperty);
WithEnumProperties bean = this.context.getBean(WithEnumProperties.class);
assertThat(bean.getTheValues()).contains(expected);
resetContext();
}
@Test
void loadShouldBindToCharArray() {
load(WithCharArrayProperties.class, "test.chars=word");
WithCharArrayProperties bean = this.context.getBean(WithCharArrayProperties.class);
assertThat(bean.getChars()).isEqualTo("word".toCharArray());
}
@Test
void loadWhenUsingRelaxedFormsAndOverrideShouldBind() {
load(WithRelaxedNamesProperties.class, "test.FOO_BAR=test1", "test.FOO_BAR=test2", "test.BAR-B-A-Z=testa",
"test.BAR-B-A-Z=testb");
WithRelaxedNamesProperties bean = this.context.getBean(WithRelaxedNamesProperties.class);
assertThat(bean.getFooBar()).isEqualTo("test2");
assertThat(bean.getBarBAZ()).isEqualTo("testb");
}
@Test
void loadShouldBindToMap() {
load(WithMapProperties.class, "test.map.foo=bar");
WithMapProperties bean = this.context.getBean(WithMapProperties.class);
assertThat(bean.getMap()).containsOnly(entry("foo", "bar"));
}
@Test
void loadShouldBindToMapWithNumericKey() {
load(MapWithNumericKeyProperties.class, "sample.properties.1.name=One");
MapWithNumericKeyProperties bean = this.context.getBean(MapWithNumericKeyProperties.class);
BasicProperties one = bean.getProperties().get("1");
assertThat(one).isNotNull();
assertThat(one.name).isEqualTo("One");
}
@Test
void loadWhenUsingSystemPropertiesShouldBindToMap() {
this.context.getEnvironment()
.getPropertySources()
.addLast(new SystemEnvironmentPropertySource(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,
Collections.singletonMap("TEST_MAP_FOO_BAR", "baz")));
load(WithComplexMapProperties.class);
WithComplexMapProperties bean = this.context.getBean(WithComplexMapProperties.class);
Map<String, Map<String, String>> map = bean.getMap();
assertThat(map).isNotNull();
assertThat(map).containsOnlyKeys("foo");
assertThat(map.get("foo")).containsOnly(entry("bar", "baz"));
}
@Test
void loadWhenDotsInSystemEnvironmentPropertiesShouldBind() {
this.context.getEnvironment()
.getPropertySources()
.addLast(new SystemEnvironmentPropertySource(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,
Collections.singletonMap("com.example.bar", "baz")));
load(SimplePrefixedProperties.class);
SimplePrefixedProperties bean = this.context.getBean(SimplePrefixedProperties.class);
assertThat(bean.getBar()).isEqualTo("baz");
}
@Test
void loadWhenEnvironmentPrefixSetShouldBind() {
MutablePropertySources sources = this.context.getEnvironment().getPropertySources();
sources.replace(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,
new SystemEnvironmentPropertySource(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,
Collections.singletonMap("MY_SPRING_FOO_NAME", "Jane")));
SpringApplication application = new SpringApplication(PrefixConfiguration.class);
application.setApplicationContextFactory((webApplicationType) -> ConfigurationPropertiesTests.this.context);
application.setEnvironmentPrefix("my");
application.setEnvironment(this.context.getEnvironment());
application.run();
BasicProperties bean = this.context.getBean(BasicProperties.class);
assertThat(bean.name).isEqualTo("Jane");
}
@Test
void loadWhenOverridingPropertiesShouldBind() {
MutablePropertySources sources = this.context.getEnvironment().getPropertySources();
sources.addFirst(
new SystemEnvironmentPropertySource("system", Collections.singletonMap("SPRING_FOO_NAME", "Jane")));
sources.addLast(new MapPropertySource("test", Collections.singletonMap("spring.foo.name", "John")));
load(PrefixConfiguration.class);
BasicProperties bean = this.context.getBean(BasicProperties.class);
assertThat(bean.name).isEqualTo("Jane");
}
@Test
void loadWhenJsr303ConstraintDoesNotMatchShouldFail() {
assertThatExceptionOfType(ConfigurationPropertiesBindException.class)
.isThrownBy(() -> load(ValidatedJsr303Configuration.class, "description="))
.withCauseInstanceOf(BindException.class);
}
@Test
void loadValidatedOnBeanMethodAndJsr303ConstraintDoesNotMatchShouldFail() {
assertThatExceptionOfType(ConfigurationPropertiesBindException.class)
.isThrownBy(() -> load(ValidatedOnBeanJsr303Configuration.class, "description="))
.withCauseInstanceOf(BindException.class);
}
@Test
void loadWhenJsr303ConstraintDoesNotMatchOnNestedThatIsNotAnnotatedWithValidShouldNotFail() {
assertThatNoException()
.isThrownBy(() -> load(ValidatedNestedJsr303Properties.class, "properties.description="));
}
@Test
void loadWhenJsr303ConstraintDoesNotMatchOnNestedThatIsNotDirectlyAnnotatedButIsValidShouldFail() {
assertThatExceptionOfType(ConfigurationPropertiesBindException.class)
.isThrownBy(() -> load(ValidatedValidNestedJsr303Properties.class))
.withCauseInstanceOf(BindException.class);
}
@Test
void loadWhenJsr303ConstraintMatchesShouldBind() {
load(ValidatedJsr303Configuration.class, "description=foo");
ValidatedJsr303Properties bean = this.context.getBean(ValidatedJsr303Properties.class);
assertThat(bean.getDescription()).isEqualTo("foo");
}
@Test
void loadWhenJsr303ConstraintDoesNotMatchAndNotValidatedAnnotationShouldBind() {
load(NonValidatedJsr303Configuration.class, "name=foo");
NonValidatedJsr303Properties bean = this.context.getBean(NonValidatedJsr303Properties.class);
assertThat(((BasicProperties) bean).name).isEqualTo("foo");
}
@Test
void loadWhenHasMultiplePropertySourcesPlaceholderConfigurerShouldLogWarning(CapturedOutput output) {
load(MultiplePropertySourcesPlaceholderConfigurerConfiguration.class);
assertThat(output).contains("Multiple PropertySourcesPlaceholderConfigurer beans registered");
}
@Test
void loadWhenOverridingPropertiesWithPlaceholderResolutionInEnvironmentShouldBindWithOverride() {
MutablePropertySources sources = this.context.getEnvironment().getPropertySources();
sources
.addFirst(new SystemEnvironmentPropertySource("system", Collections.singletonMap("COM_EXAMPLE_BAR", "10")));
Map<String, Object> source = new HashMap<>();
source.put("com.example.bar", 5);
source.put("com.example.foo", "${com.example.bar}");
sources.addLast(new MapPropertySource("test", source));
load(SimplePrefixedProperties.class);
SimplePrefixedProperties bean = this.context.getBean(SimplePrefixedProperties.class);
assertThat(bean.getFoo()).isEqualTo(10);
}
@Test
void loadWhenHasUnboundElementsFromSystemEnvironmentShouldNotThrowException() {
MutablePropertySources sources = this.context.getEnvironment().getPropertySources();
sources.addFirst(new MapPropertySource("test", Collections.singletonMap("com.example.foo", 5)));
sources.addLast(new SystemEnvironmentPropertySource(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,
Collections.singletonMap("COM_EXAMPLE_OTHER", "10")));
load(SimplePrefixedProperties.class);
SimplePrefixedProperties bean = this.context.getBean(SimplePrefixedProperties.class);
assertThat(bean.getFoo()).isEqualTo(5);
}
@Test
void loadShouldSupportRebindableConfigurationPropertiesRegisteredAsBean() {
testRebindableConfigurationProperties(PrototypePropertiesBeanConfiguration.class);
}
@Test
void loadShouldSupportRebindableConfigurationPropertiesRegisteredUsingRegistrar() {
testRebindableConfigurationProperties(PrototypePropertiesRegistrarConfiguration.class);
}
void testRebindableConfigurationProperties(Class<?> configurationClass) {
MutablePropertySources sources = this.context.getEnvironment().getPropertySources();
Map<String, Object> source = new LinkedHashMap<>();
source.put("example.one", "foo");
sources.addFirst(new MapPropertySource("test-source", source));
this.context.register(configurationClass);
this.context.refresh();
PrototypeBean first = this.context.getBean(PrototypeBean.class);
assertThat(first.getOne()).isEqualTo("foo");
source.put("example.one", "bar");
sources.addFirst(new MapPropertySource("extra", Collections.singletonMap("example.two", "baz")));
PrototypeBean second = this.context.getBean(PrototypeBean.class);
assertThat(second.getOne()).isEqualTo("bar");
assertThat(second.getTwo()).isEqualTo("baz");
}
@Test
void loadWhenHasPropertySourcesPlaceholderConfigurerShouldSupportRebindableConfigurationPropertiesRegisteredAsBean() {
testPropertySourcesPlaceholderConfigurerShouldSupportRebindableConfigurationProperties(
PrototypePropertiesBeanConfiguration.class);
}
@Test
void loadWhenHasPropertySourcesPlaceholderConfigurerShouldSupportRebindableConfigurationPropertiesRegisteredUsingRegistrar() {
testPropertySourcesPlaceholderConfigurerShouldSupportRebindableConfigurationProperties(
PrototypePropertiesRegistrarConfiguration.class);
}
void testPropertySourcesPlaceholderConfigurerShouldSupportRebindableConfigurationProperties(
Class<?> configurationClass) {
MutablePropertySources sources = this.context.getEnvironment().getPropertySources();
Map<String, Object> source = new LinkedHashMap<>();
source.put("example.one", "foo");
sources.addFirst(new MapPropertySource("test-source", source));
this.context.register(configurationClass);
this.context.register(PropertySourcesPlaceholderConfigurer.class);
this.context.refresh();
PrototypeBean first = this.context.getBean(PrototypeBean.class);
assertThat(first.getOne()).isEqualTo("foo");
source.put("example.one", "bar");
sources.addFirst(new MapPropertySource("extra", Collections.singletonMap("example.two", "baz")));
PrototypeBean second = this.context.getBean(PrototypeBean.class);
assertThat(second.getOne()).isEqualTo("bar");
assertThat(second.getTwo()).isEqualTo("baz");
}
@Test
void customProtocolResolverIsInvoked() {
this.context = new AnnotationConfigApplicationContext();
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context, "test.resource=application.properties");
ProtocolResolver protocolResolver = mock(ProtocolResolver.class);
given(protocolResolver.resolve(anyString(), any(ResourceLoader.class))).willReturn(null);
this.context.addProtocolResolver(protocolResolver);
this.context.register(PropertiesWithResource.class);
this.context.refresh();
then(protocolResolver).should().resolve(eq("application.properties"), any(ResourceLoader.class));
}
@Test
@WithResource(name = "application.properties")
void customProtocolResolver() {
this.context = new AnnotationConfigApplicationContext();
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context,
"test.resource=test:/application.properties");
this.context.addProtocolResolver(new TestProtocolResolver());
this.context.register(PropertiesWithResource.class);
this.context.refresh();
Resource resource = this.context.getBean(PropertiesWithResource.class).getResource();
assertThat(resource).isNotNull();
assertThat(resource).isInstanceOf(ClassPathResource.class);
assertThat(resource.exists()).isTrue();
assertThat(((ClassPathResource) resource).getPath()).isEqualTo("application.properties");
}
@Test
void loadShouldUseConverterBean() {
prepareConverterContext(PersonConverterConfiguration.class, PersonProperties.class);
Person person = this.context.getBean(PersonProperties.class).getPerson();
assertThat(person).isNotNull();
assertThat(person.firstName).isEqualTo("John");
assertThat(person.lastName).isEqualTo("Smith");
}
@Test
void loadShouldUseStringConverterBeanWhenValueIsCharSequence() {
this.context.register(PersonConverterConfiguration.class, PersonProperties.class);
PropertySource<?> testProperties = new MapPropertySource("test", Map.of("test.person", new CharSequence() {
private final String value = "John Smith";
@Override
public int length() {
return this.value.length();
}
@Override
public char charAt(int index) {
return this.value.charAt(index);
}
@Override
public CharSequence subSequence(int start, int end) {
return this.value.subSequence(start, end);
}
@Override
public String toString() {
return this.value;
}
}));
this.context.getEnvironment().getPropertySources().addLast(testProperties);
this.context.refresh();
Person person = this.context.getBean(PersonProperties.class).getPerson();
assertThat(person).isNotNull();
assertThat(person.firstName).isEqualTo("John");
assertThat(person.lastName).isEqualTo("Smith");
}
@Test
void loadWhenBeanFactoryConversionServiceAndConverterBeanCanUseBeanFactoryConverter() {
DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new AlienConverter());
this.context.getBeanFactory().setConversionService(conversionService);
load(new Class<?>[] { PersonConverterConfiguration.class, PersonAndAlienProperties.class },
"test.person=John Smith", "test.alien=Alf Tanner");
PersonAndAlienProperties properties = this.context.getBean(PersonAndAlienProperties.class);
Person person = properties.getPerson();
assertThat(person).isNotNull();
assertThat(person.firstName).isEqualTo("John");
assertThat(person.lastName).isEqualTo("Smith");
Alien alien = properties.getAlien();
assertThat(alien).isNotNull();
assertThat(alien.name).isEqualTo("rennaT flA");
}
@Test
void loadWhenBeanFactoryConversionServiceAndConverterBeanCanUseConverterBean() {
DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new PersonConverter());
this.context.getBeanFactory().setConversionService(conversionService);
load(new Class<?>[] { AlienConverterConfiguration.class, PersonAndAlienProperties.class },
"test.person=John Smith", "test.alien=Alf Tanner");
PersonAndAlienProperties properties = this.context.getBean(PersonAndAlienProperties.class);
Person person = properties.getPerson();
assertThat(person).isNotNull();
assertThat(person.firstName).isEqualTo("John");
assertThat(person.lastName).isEqualTo("Smith");
Alien alien = properties.getAlien();
assertThat(alien).isNotNull();
assertThat(alien.name).isEqualTo("rennaT flA");
}
@Test // gh-38734
void loadWhenBeanFactoryConversionServiceAndConverterBeanCanUseConverterBeanWithCollections() {
DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new PersonConverter());
this.context.getBeanFactory().setConversionService(conversionService);
load(new Class<?>[] { AlienConverterConfiguration.class, PersonAndAliensProperties.class },
"test.person=John Smith", "test.aliens=Alf Tanner,Gilbert");
PersonAndAliensProperties properties = this.context.getBean(PersonAndAliensProperties.class);
Person person = properties.getPerson();
assertThat(person).isNotNull();
assertThat(person.firstName).isEqualTo("John");
assertThat(person.lastName).isEqualTo("Smith");
List<Alien> aliens = properties.getAliens();
assertThat(aliens).isNotNull();
assertThat(aliens.get(0).name).isEqualTo("rennaT flA");
assertThat(aliens.get(1).name).isEqualTo("trebliG");
}
@Test
void loadWhenConfigurationConverterIsNotQualifiedShouldNotConvert() {
assertThatExceptionOfType(BeanCreationException.class)
.isThrownBy(() -> prepareConverterContext(NonQualifiedConverterConfiguration.class, PersonProperties.class))
.withCauseInstanceOf(BindException.class);
}
@Test
void loadShouldUseGenericConverterBean() {
prepareConverterContext(GenericConverterConfiguration.class, PersonProperties.class);
Person person = this.context.getBean(PersonProperties.class).getPerson();
assertThat(person).isNotNull();
assertThat(person.firstName).isEqualTo("John");
assertThat(person.lastName).isEqualTo("Smith");
}
@Test
void loadShouldUseFormatterBean() {
prepareConverterContext(FormatterConfiguration.class, PersonProperties.class);
Person person = this.context.getBean(PersonProperties.class).getPerson();
assertThat(person).isNotNull();
assertThat(person.firstName).isEqualTo("John");
assertThat(person.lastName).isEqualTo("Smith");
}
@Test
void loadWhenGenericConfigurationConverterIsNotQualifiedShouldNotConvert() {
assertThatExceptionOfType(BeanCreationException.class).isThrownBy(
() -> prepareConverterContext(NonQualifiedGenericConverterConfiguration.class, PersonProperties.class))
.withCauseInstanceOf(BindException.class);
}
@Test
@SuppressWarnings("rawtypes")
void loadShouldBindToBeanWithGenerics() {
load(GenericConfiguration.class, "foo.bar=hello");
AGenericClass foo = this.context.getBean(AGenericClass.class);
assertThat(foo.getBar()).isNotNull();
}
private void prepareConverterContext(Class<?>... config) {
load(config, "test.person=John Smith");
}
@Test
void loadWhenHasConfigurationPropertiesValidatorShouldApplyValidator() {
assertThatException().isThrownBy(() -> load(WithCustomValidatorConfiguration.class)).satisfies((ex) -> {
assertThat(ex).hasCauseInstanceOf(BindException.class);
assertThat(ex.getCause()).hasCauseExactlyInstanceOf(BindValidationException.class);
});
}
@Test
void loadWhenHasUnsupportedConfigurationPropertiesValidatorShouldBind() {
load(WithUnsupportedCustomValidatorConfiguration.class, "test.foo=bar");
WithSetterThatThrowsValidationExceptionProperties bean = this.context
.getBean(WithSetterThatThrowsValidationExceptionProperties.class);
assertThat(bean.getFoo()).isEqualTo("bar");
}
@Test
void loadWhenConfigurationPropertiesIsAlsoValidatorShouldApplyValidator() {
assertThatException().isThrownBy(() -> load(ValidatorProperties.class)).satisfies((ex) -> {
assertThat(ex).hasCauseInstanceOf(BindException.class);
assertThat(ex.getCause()).hasCauseExactlyInstanceOf(BindValidationException.class);
});
}
@Test
void loadWhenConstructorBoundConfigurationPropertiesIsAlsoValidatorShouldApplyValidator() {
assertThatException().isThrownBy(() -> load(ValidatorConstructorBoundPropertiesConfiguration.class))
.satisfies((ex) -> {
assertThat(ex).hasCauseInstanceOf(BindException.class);
assertThat(ex.getCause()).hasCauseExactlyInstanceOf(BindValidationException.class);
});
}
@Test
void loadWhenConfigurationPropertiesWithValidDefaultValuesShouldNotFail() {
AnnotationConfigApplicationContext context = load(ValidatorPropertiesWithDefaultValues.class);
ValidatorPropertiesWithDefaultValues bean = context.getBean(ValidatorPropertiesWithDefaultValues.class);
assertThat(bean.getBar()).isEqualTo("a");
}
@Test
void loadWhenSetterThrowsValidationExceptionShouldFail() {
assertThatExceptionOfType(BeanCreationException.class)
.isThrownBy(() -> load(WithSetterThatThrowsValidationExceptionProperties.class, "test.foo=spam"))
.withCauseInstanceOf(BindException.class);
}
@Test
void loadWhenFailsShouldIncludeAnnotationDetails() {
removeSystemProperties();
assertThatExceptionOfType(ConfigurationPropertiesBindException.class)
.isThrownBy(() -> load(IgnoreUnknownFieldsFalseConfiguration.class, "name=foo", "bar=baz"))
.withMessageContaining("Could not bind properties to "
+ "'ConfigurationPropertiesTests.IgnoreUnknownFieldsFalseProperties' : "
+ "prefix=, ignoreInvalidFields=false, ignoreUnknownFields=false");
}
@Test
void loadWhenHasCustomPropertyEditorShouldBind() {
this.context.getBeanFactory().registerCustomEditor(Person.class, PersonPropertyEditor.class);
load(PersonProperties.class, "test.person=boot,spring");
PersonProperties bean = this.context.getBean(PersonProperties.class);
Person person = bean.getPerson();
assertThat(person).isNotNull();
assertThat(person.firstName).isEqualTo("spring");
assertThat(person.lastName).isEqualTo("boot");
}
@Test
void loadWhenBindingToListOfGenericClassShouldBind() {
// gh-12166
load(ListOfGenericClassProperties.class, "test.list=java.lang.RuntimeException");
ListOfGenericClassProperties bean = this.context.getBean(ListOfGenericClassProperties.class);
assertThat(bean.getList()).containsExactly(RuntimeException.class);
}
@Test
void loadWhenBindingCurrentDirectoryToFileShouldBind() {
load(FileProperties.class, "test.file=.");
FileProperties bean = this.context.getBean(FileProperties.class);
assertThat(bean.getFile()).isEqualTo(new File("."));
}
@Test
void loadWhenBindingToDataSizeShouldBind() {
load(DataSizeProperties.class, "test.size=10GB", "test.another-size=5");
DataSizeProperties bean = this.context.getBean(DataSizeProperties.class);
assertThat(bean.getSize()).isEqualTo(DataSize.ofGigabytes(10));
assertThat(bean.getAnotherSize()).isEqualTo(DataSize.ofKilobytes(5));
}
@Test
void loadWhenTopLevelConverterNotFoundExceptionShouldNotFail() {
load(PersonProperties.class, "test=boot");
}
@Test
void loadWhenConfigurationPropertiesContainsMapWithPositiveAndNegativeIntegerKeys() {
// gh-14136
MutablePropertySources sources = this.context.getEnvironment().getPropertySources();
Map<String, Object> source = new HashMap<>();
source.put("test.map.x.[-1].a", "baz");
source.put("test.map.x.1.a", "bar");
source.put("test.map.x.1.b", 1);
sources.addLast(new MapPropertySource("test", source));
load(WithIntegerMapProperties.class);
WithIntegerMapProperties bean = this.context.getBean(WithIntegerMapProperties.class);
Map<String, Map<Integer, Foo>> map = bean.getMap();
assertThat(map).isNotNull();
Map<Integer, Foo> x = map.get("x");
assertThat(x).isNotNull();
Foo minus1 = x.get(-1);
assertThat(minus1).isNotNull();
assertThat(minus1.getA()).isEqualTo("baz");
assertThat(minus1.getB()).isZero();
Foo one = x.get(1);
assertThat(one).isNotNull();
assertThat(one.getA()).isEqualTo("bar");
assertThat(one.getB()).isOne();
}
@Test
void loadWhenConfigurationPropertiesInjectsAnotherBeanShouldNotFail() {
assertThatExceptionOfType(ConfigurationPropertiesBindException.class)
.isThrownBy(() -> load(OtherInjectPropertiesConfiguration.class))
.havingCause()
.isInstanceOf(BindException.class)
.withMessageContaining(OtherInjectedProperties.class.getName())
.withMessageContaining("Failed to bind properties under 'test'");
}
@Test
void loadWhenBindingToConstructorParametersShouldBind() {
MutablePropertySources sources = this.context.getEnvironment().getPropertySources();
Map<String, Object> source = new HashMap<>();
source.put("test.foo", "baz");
source.put("test.bar", "5");
sources.addLast(new MapPropertySource("test", source));
load(ConstructorParameterConfiguration.class);
ConstructorParameterProperties bean = this.context.getBean(ConstructorParameterProperties.class);
assertThat(bean.getFoo()).isEqualTo("baz");
assertThat(bean.getBar()).isEqualTo(5);
}
@Test
void loadWhenBindingToConstructorParametersWithCustomDataUnitShouldBind() {
MutablePropertySources sources = this.context.getEnvironment().getPropertySources();
Map<String, Object> source = new HashMap<>();
source.put("test.duration", "12");
source.put("test.size", "13");
source.put("test.period", "14");
sources.addLast(new MapPropertySource("test", source));
load(ConstructorParameterWithUnitConfiguration.class);
ConstructorParameterWithUnitProperties bean = this.context
.getBean(ConstructorParameterWithUnitProperties.class);
assertThat(bean.getDuration()).isEqualTo(Duration.ofDays(12));
assertThat(bean.getSize()).isEqualTo(DataSize.ofMegabytes(13));
assertThat(bean.getPeriod()).isEqualTo(Period.ofYears(14));
}
@Test
void loadWhenBindingToConstructorParametersWithDefaultValuesShouldBind() {
load(ConstructorParameterConfiguration.class);
ConstructorParameterProperties bean = this.context.getBean(ConstructorParameterProperties.class);
assertThat(bean.getFoo()).isEqualTo("hello");
assertThat(bean.getBar()).isZero();
}
@Test
void loadWhenBindingToConstructorParametersWithEmptyDefaultValueShouldBind() {
load(ConstructorParameterEmptyDefaultValueConfiguration.class);
ConstructorParameterEmptyDefaultValueProperties bean = this.context
.getBean(ConstructorParameterEmptyDefaultValueProperties.class);
assertThat(bean.getSet()).isEmpty();
assertThat(bean.getMap()).isEmpty();
assertThat(bean.getArray()).isEmpty();
assertThat(bean.getOptional()).isEmpty();
}
@Test
void loadWhenBindingToConstructorParametersWithDefaultDataUnitShouldBind() {
load(ConstructorParameterWithUnitConfiguration.class);
ConstructorParameterWithUnitProperties bean = this.context
.getBean(ConstructorParameterWithUnitProperties.class);
assertThat(bean.getDuration()).isEqualTo(Duration.ofDays(2));
assertThat(bean.getSize()).isEqualTo(DataSize.ofMegabytes(3));
assertThat(bean.getPeriod()).isEqualTo(Period.ofYears(4));
}
@Test
void loadWhenBindingToConstructorParametersWithCustomDataFormatShouldBind() {
MutablePropertySources sources = this.context.getEnvironment().getPropertySources();
Map<String, Object> source = new HashMap<>();
source.put("test.duration", "12d");
source.put("test.period", "13y");
sources.addLast(new MapPropertySource("test", source));
load(ConstructorParameterWithFormatConfiguration.class);
ConstructorParameterWithFormatProperties bean = this.context
.getBean(ConstructorParameterWithFormatProperties.class);
assertThat(bean.getDuration()).isEqualTo(Duration.ofDays(12));
assertThat(bean.getPeriod()).isEqualTo(Period.ofYears(13));
}
@Test
void loadWhenBindingToConstructorParametersWithNotMatchingCustomDurationFormatShouldFail() {
MutablePropertySources sources = this.context.getEnvironment().getPropertySources();
Map<String, Object> source = new HashMap<>();
source.put("test.duration", "P12D");
sources.addLast(new MapPropertySource("test", source));
assertThatException().isThrownBy(() -> load(ConstructorParameterWithFormatConfiguration.class))
.havingCause()
.isInstanceOf(BindException.class);
}
@Test
void loadWhenBindingToConstructorParametersWithNotMatchingCustomPeriodFormatShouldFail() {
MutablePropertySources sources = this.context.getEnvironment().getPropertySources();
Map<String, Object> source = new HashMap<>();
source.put("test.period", "P12D");
sources.addLast(new MapPropertySource("test", source));
assertThatException().isThrownBy(() -> load(ConstructorParameterWithFormatConfiguration.class))
.havingCause()
.isInstanceOf(BindException.class);
}
@Test
void loadWhenBindingToConstructorParametersWithDefaultDataFormatShouldBind() {
load(ConstructorParameterWithFormatConfiguration.class);
ConstructorParameterWithFormatProperties bean = this.context
.getBean(ConstructorParameterWithFormatProperties.class);
assertThat(bean.getDuration()).isEqualTo(Duration.ofDays(2));
assertThat(bean.getPeriod()).isEqualTo(Period.ofYears(3));
}
@Test
void loadWhenBindingToConstructorParametersShouldValidate() {
assertThatException().isThrownBy(() -> load(ConstructorParameterValidationConfiguration.class))
.satisfies((ex) -> {
assertThat(ex).hasCauseInstanceOf(BindException.class);
assertThat(ex.getCause()).hasCauseExactlyInstanceOf(BindValidationException.class);
});
}
@Test
void loadWhenBindingOnBeanWithoutBeanDefinitionShouldBind() {
load(BasicConfiguration.class, "name=test");
BasicProperties bean = this.context.getBean(BasicProperties.class);
assertThat(bean.name).isEqualTo("test");
bean.name = "override";
this.context.getBean(ConfigurationPropertiesBindingPostProcessor.class)
.postProcessBeforeInitialization(bean, "does-not-exist");
assertThat(bean.name).isEqualTo("test");
}
@Test
void loadWhenBindingToNestedConstructorPropertiesShouldBind() {
MutablePropertySources sources = this.context.getEnvironment().getPropertySources();
Map<String, Object> source = new HashMap<>();
source.put("test.name", "spring");
source.put("test.nested.age", "5");
sources.addLast(new MapPropertySource("test", source));
load(NestedConstructorPropertiesConfiguration.class);
NestedConstructorProperties bean = this.context.getBean(NestedConstructorProperties.class);
assertThat(bean.getName()).isEqualTo("spring");
assertThat(bean.getNested().getAge()).isEqualTo(5);
}
@Test // gh-18485
void loadWhenBindingToMultiConstructorConfigurationProperties() {
MutablePropertySources sources = this.context.getEnvironment().getPropertySources();
Map<String, Object> source = new HashMap<>();
source.put("test.nested[0].name", "spring");
source.put("test.nested[0].age", "5");
sources.addLast(new MapPropertySource("test", source));
load(MultiConstructorConfigurationPropertiesConfiguration.class);
MultiConstructorConfigurationListProperties bean = this.context
.getBean(MultiConstructorConfigurationListProperties.class);
MultiConstructorConfigurationProperties nested = bean.getNested().get(0);
assertThat(nested.getName()).isEqualTo("spring");
assertThat(nested.getAge()).isEqualTo(5);
}
@Test // gh-18485
void loadWhenBindingToMultiConstructorConfigurationPropertiesUsingShortcutSyntax() {
MutablePropertySources sources = this.context.getEnvironment().getPropertySources();
Map<String, Object> source = new HashMap<>();
source.put("test.nested[0]", "spring");
sources.addLast(new MapPropertySource("test", source));
load(MultiConstructorConfigurationPropertiesConfiguration.class);
MultiConstructorConfigurationListProperties bean = this.context
.getBean(MultiConstructorConfigurationListProperties.class);
MultiConstructorConfigurationProperties nested = bean.getNested().get(0);
assertThat(nested.getName()).isEqualTo("spring");
assertThat(nested.getAge()).isZero();
}
@Test // gh-18481
void loadWhenBindingToNestedConstructorPropertiesWithDeducedNestedShouldBind() {
MutablePropertySources sources = this.context.getEnvironment().getPropertySources();
Map<String, Object> source = new HashMap<>();
source.put("test.name", "spring");
source.put("test.nested.age", "5");
sources.addLast(new MapPropertySource("test", source));
load(DeducedNestedConstructorPropertiesConfiguration.class);
DeducedNestedConstructorProperties bean = this.context.getBean(DeducedNestedConstructorProperties.class);
assertThat(bean.getName()).isEqualTo("spring");
assertThat(bean.getNested().getAge()).isEqualTo(5);
}
@Test
void loadWhenBindingToNestedPropertiesWithSyntheticConstructorShouldBind() {
MutablePropertySources sources = this.context.getEnvironment().getPropertySources();
Map<String, Object> source = new HashMap<>();
source.put("test.nested.age", "5");
sources.addLast(new MapPropertySource("test", source));
load(SyntheticConstructorPropertiesConfiguration.class);
SyntheticNestedConstructorProperties bean = this.context.getBean(SyntheticNestedConstructorProperties.class);
assertThat(bean.getNested().getAge()).isEqualTo(5);
}
@Test
void loadWhenBindingToJavaBeanWithNestedConstructorBindingShouldBind() {
MutablePropertySources sources = this.context.getEnvironment().getPropertySources();
Map<String, Object> source = new HashMap<>();
source.put("test.nested.age", "5");
sources.addLast(new MapPropertySource("test", source));
load(JavaBeanNestedConstructorBindingPropertiesConfiguration.class);
JavaBeanNestedConstructorBindingProperties bean = this.context
.getBean(JavaBeanNestedConstructorBindingProperties.class);
Nested nested = bean.getNested();
assertThat(nested).isNotNull();
assertThat(nested.getAge()).isEqualTo(5);
}
@Test
void loadWhenBindingToNestedWithMultipleConstructorsShouldBind() {
MutablePropertySources sources = this.context.getEnvironment().getPropertySources();
Map<String, Object> source = new HashMap<>();
source.put("test.nested.age", "5");
sources.addLast(new MapPropertySource("test", source));
load(NestedMultipleConstructorsConfiguration.class);
NestedMultipleConstructorProperties bean = this.context.getBean(NestedMultipleConstructorProperties.class);
assertThat(bean.getNested().getAge()).isEqualTo(5);
}
@Test
void loadWhenBindingToJavaBeanWithoutExplicitConstructorBindingOnNestedShouldUseSetterBasedBinding() {
MutablePropertySources sources = this.context.getEnvironment().getPropertySources();
Map<String, Object> source = new HashMap<>();
source.put("test.nested.age", "5");
sources.addLast(new MapPropertySource("test", source));
load(JavaBeanNonDefaultConstructorPropertiesConfiguration.class);
JavaBeanNonDefaultConstructorProperties bean = this.context
.getBean(JavaBeanNonDefaultConstructorProperties.class);
JavaBeanNonDefaultConstructorProperties.Nested nested = bean.getNested();
assertThat(nested).isNotNull();
assertThat(nested.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);
}
@Test
void loadWhenConstructorBindingWithOuterClassDeducedConstructorBound() {
MutablePropertySources sources = this.context.getEnvironment().getPropertySources();
Map<String, Object> source = new HashMap<>();
source.put("test.nested.outer.age", "5");
sources.addLast(new MapPropertySource("test", source));
load(ConstructorBindingWithOuterClassConstructorBoundConfiguration.class);
ConstructorBindingWithOuterClassConstructorBoundProperties bean = this.context
.getBean(ConstructorBindingWithOuterClassConstructorBoundProperties.class);
Outer outer = bean.getNested().getOuter();
assertThat(outer).isNotNull();
assertThat(outer.getAge()).isEqualTo(5);
}
@Test
void loadWhenConstructorBindingWithOuterClassAndNestedAutowiredShouldThrowException() {
MutablePropertySources sources = this.context.getEnvironment().getPropertySources();
Map<String, Object> source = new HashMap<>();
source.put("test.nested.age", "5");
sources.addLast(new MapPropertySource("test", source));
assertThatExceptionOfType(ConfigurationPropertiesBindException.class).isThrownBy(
() -> load(ConstructorBindingWithOuterClassConstructorBoundAndNestedAutowiredConfiguration.class));
}
@Test
void loadWhenConfigurationPropertiesPrefixMatchesPropertyInEnvironment() {
MutablePropertySources sources = this.context.getEnvironment().getPropertySources();
Map<String, Object> source = new HashMap<>();
source.put("test", "bar");
source.put("test.a", "baz");
sources.addLast(new MapPropertySource("test", source));
load(WithPublicStringConstructorPropertiesConfiguration.class);
WithPublicStringConstructorProperties bean = this.context.getBean(WithPublicStringConstructorProperties.class);
assertThat(bean.getA()).isEqualTo("baz");
}
@Test // gh-26201
void loadWhenBoundToRandomPropertyPlaceholder() {
MutablePropertySources sources = this.context.getEnvironment().getPropertySources();
sources.addFirst(new RandomValuePropertySource());
Map<String, Object> source = new HashMap<>();
source.put("com.example.bar", "${random.int[100,200]}");
sources.addLast(new MapPropertySource("test", source));
load(SimplePrefixedProperties.class);
SimplePrefixedProperties bean = this.context.getBean(SimplePrefixedProperties.class);
assertThat(bean.getBar()).isNotNull().containsOnlyDigits();
}
@Test
void boundPropertiesShouldBeRecorded() {
load(NestedConfiguration.class, "name=foo", "nested.name=bar");
BoundConfigurationProperties bound = BoundConfigurationProperties.get(this.context);
assertThat(bound).isNotNull();
Set<ConfigurationPropertyName> keys = bound.getAll().keySet();
assertThat(keys.stream().map(ConfigurationPropertyName::toString)).contains("name", "nested.name");
}
@Test // gh-28592
void loadWhenBindingWithCustomConverterAndObjectToObjectMethod() {
this.context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance());
load(WithCustomConverterAndObjectToObjectMethodConfiguration.class, "test.item=foo");
WithCustomConverterAndObjectToObjectMethodProperties bean = this.context
.getBean(WithCustomConverterAndObjectToObjectMethodProperties.class);
WithPublicObjectToObjectMethod item = bean.getItem();
assertThat(item).isNotNull();
assertThat(item.getValue()).isEqualTo("foo");
}
@Test // gh-33710
void loadWhenConstructorUsedInBeanMethodAndNotAsConstructorBinding() {
load(ConstructorUsedInBeanMethodConfiguration.class, "test.two=bound-2");
ConstructorUsedDirectly bean = this.context.getBean(ConstructorUsedDirectly.class);
assertThat(bean.getOne()).isEqualTo("bean-method-1");
assertThat(bean.getTwo()).isEqualTo("bound-2");
}
@Test // gh-33409
void loadWhenConstructorUsedInNestedPropertyAndNotAsConstructorBinding() {
load(ConstructorUsedInNestedPropertyConfiguration.class, "test.nested.two=bound-2");
ConstructorUsedInNestedProperty bean = this.context.getBean(ConstructorUsedInNestedProperty.class);
assertThat(bean.getNested().getOne()).isEqualTo("nested-1");
assertThat(bean.getNested().getTwo()).isEqualTo("bound-2");
}
@Test // gh-34407
void loadWhenNestedRecordWithExistingInstance() {
load(NestedRecordInstancePropertiesConfiguration.class, "test.nested.name=spring");
NestedRecordInstanceProperties bean = this.context.getBean(NestedRecordInstanceProperties.class);
assertThat(bean.getNested().name()).isEqualTo("spring");
}
@Test
void loadWhenPotentiallyConstructorBoundPropertiesAreImportedUsesJavaBeanBinding() {
load(PotentiallyConstructorBoundPropertiesImporter.class, "test.prop=alpha");
PotentiallyConstructorBoundProperties properties = this.context
.getBean(PotentiallyConstructorBoundProperties.class);
assertThat(properties.getProp()).isEqualTo("alpha");
}
@Test
void loadWhenBindingClasspathPatternToResourceArrayShouldBindMultipleValues() {
load(ResourceArrayPropertiesConfiguration.class,
"test.resources=classpath*:org/springframework/boot/context/properties/*.class");
ResourceArrayProperties properties = this.context.getBean(ResourceArrayProperties.class);
assertThat(properties.getResources()).hasSizeGreaterThan(1);
}
@Test
void loadWhenBindingClasspathPatternToResourceCollectionShouldBindMultipleValues() {
load(ResourceCollectionPropertiesConfiguration.class,
"test.resources=classpath*:org/springframework/boot/context/properties/*.class");
ResourceCollectionProperties properties = this.context.getBean(ResourceCollectionProperties.class);
assertThat(properties.getResources()).hasSizeGreaterThan(1);
}
@Test
void loadWhenBindingToConstructorParametersWithConversionToCustomListImplementation() {
load(ConstructorBoundCustomListPropertiesConfiguration.class, "test.values=a,b");
assertThat(this.context.getBean(ConstructorBoundCustomListProperties.class).getValues()).containsExactly("a",
"b");
}
@Test
void loadWhenBindingToJavaBeanWithConversionToCustomListImplementation() {
load(SetterBoundCustomListPropertiesConfiguration.class, "test.values=a,b");
assertThat(this.context.getBean(SetterBoundCustomListProperties.class).getValues()).containsExactly("a", "b");
}
private AnnotationConfigApplicationContext load(Class<?> configuration, String... inlinedProperties) {
return load(new Class<?>[] { configuration }, inlinedProperties);
}
private AnnotationConfigApplicationContext load(Class<?>[] configuration, String... inlinedProperties) {
this.context.register(configuration);
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context, inlinedProperties);
this.context.refresh();
return this.context;
}
/**
* Strict tests need a known set of properties so we remove system items which may be
* environment specific.
*/
private void removeSystemProperties() {
MutablePropertySources sources = this.context.getEnvironment().getPropertySources();
sources.remove("systemProperties");
sources.remove("systemEnvironment");
}
private void resetContext() {
this.context.close();
this.context = new AnnotationConfigApplicationContext();
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
static class TestConfiguration {
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(BasicProperties.class)
static class BasicConfiguration {
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(NestedProperties.class)
static class NestedConfiguration {
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(IgnoreUnknownFieldsFalseProperties.class)
static class IgnoreUnknownFieldsFalseConfiguration {
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(IgnoreUnknownFieldsFalseIgnoreInvalidFieldsTrueProperties.class)
static class IgnoreUnknownFieldsFalseIgnoreInvalidFieldsTrueConfiguration {
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(PrefixProperties.class)
static class PrefixConfiguration {
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(ValidatedJsr303Properties.class)
static class ValidatedJsr303Configuration {
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
static class ValidatedOnBeanJsr303Configuration {
@Bean
@Validated
NonValidatedJsr303Properties properties() {
return new NonValidatedJsr303Properties();
}
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(NonValidatedJsr303Properties.class)
static class NonValidatedJsr303Configuration {
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(AnnotationOnBaseClassProperties.class)
static class AnnotationOnBaseClassConfiguration {
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(WithoutAndAnnotationConfiguration.class)
static class WithoutAndAnnotationConfiguration {
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(WithoutAnnotationValueProperties.class)
static class WithoutAnnotationValueConfiguration {
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
@ImportResource("testProperties.xml")
static class DefaultsInXmlConfiguration {
}
@Configuration(proxyBeanMethods = false)
static class DefaultsInJavaConfiguration {
@Bean
BasicProperties basicProperties() {
BasicProperties test = new BasicProperties();
test.setName("bar");
return test;
}
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
static class PrefixPropertiesDeclaredAsBeanConfiguration {
@Bean
PrefixProperties prefixProperties() {
return new PrefixProperties();
}
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(PrefixProperties.class)
static class PrefixPropertiesDeclaredAsAnnotationValueConfiguration {
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties({ PrefixProperties.class, AnotherPrefixProperties.class })
static class MultiplePrefixPropertiesDeclaredAsAnnotationValueConfiguration {
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
static class PrefixedPropertiesReplacedOnBeanMethodConfiguration {
@Bean
@ConfigurationProperties("spam")
PrefixProperties prefixProperties() {
return new PrefixProperties();
}
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
static class ValidatedImplementationConfiguration {
@Bean
ValidatedImplementationProperties testProperties() {
return new ValidatedImplementationProperties();
}
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
@ConfigurationProperties
static class WithPostConstructConfiguration {
private @Nullable String bar;
private boolean initialized;
void setBar(@Nullable String bar) {
this.bar = bar;
}
@Nullable String getBar() {
return this.bar;
}
@PostConstruct
void init() {
assertThat(this.bar).isNotNull();
this.initialized = true;
}
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(WithPropertyPlaceholderValueProperties.class)
static class WithPropertyPlaceholderValueConfiguration {
@Bean
static PropertySourcesPlaceholderConfigurer configurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(SimplePrefixedProperties.class)
static class WithPropertyPlaceholderWithLocalPropertiesValueConfiguration {
@Bean
static PropertySourcesPlaceholderConfigurer configurer() {
PropertySourcesPlaceholderConfigurer placeholderConfigurer = new PropertySourcesPlaceholderConfigurer();
Properties properties = new Properties();
properties.put("com.example.bar", "b");
placeholderConfigurer.setProperties(properties);
return placeholderConfigurer;
}
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
static class WithFactoryBeanConfiguration {
static boolean factoryBeanInitialized;
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
static class MultiplePropertySourcesPlaceholderConfigurerConfiguration {
@Bean
static PropertySourcesPlaceholderConfigurer configurer1() {
return new PropertySourcesPlaceholderConfigurer();
}
@Bean
static PropertySourcesPlaceholderConfigurer configurer2() {
return new PropertySourcesPlaceholderConfigurer();
}
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
static class PrototypePropertiesBeanConfiguration {
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@ConfigurationProperties("example")
PrototypeBean prototypeBean() {
return new PrototypeBean();
}
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(PrototypeBeanProperties.class)
static class PrototypePropertiesRegistrarConfiguration {
}
@ConfigurationProperties("example")
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
static class PrototypeBeanProperties extends PrototypeBean {
}
@EnableConfigurationProperties
@ConfigurationProperties("test")
static class PropertiesWithResource {
private @Nullable Resource resource;
@Nullable Resource getResource() {
return this.resource;
}
void setResource(@Nullable Resource resource) {
this.resource = resource;
}
}
static class TestProtocolResolver implements ProtocolResolver {
static final String PREFIX = "test:/";
@Override
public @Nullable Resource resolve(String location, ResourceLoader resourceLoader) {
if (location.startsWith(PREFIX)) {
String path = location.substring(PREFIX.length());
return new ClassPathResource(path);
}
return null;
}
}
@Configuration(proxyBeanMethods = false)
static class PersonConverterConfiguration {
@Bean
@ConfigurationPropertiesBinding
static Converter<String, Person> personConverter() {
return new PersonConverter();
}
}
@Configuration(proxyBeanMethods = false)
static class AlienConverterConfiguration {
@Bean
@ConfigurationPropertiesBinding
static Converter<String, Alien> alienConverter() {
return new AlienConverter();
}
}
@Configuration(proxyBeanMethods = false)
static class NonQualifiedConverterConfiguration {
@Bean
Converter<String, Person> personConverter() {
return new PersonConverter();
}
}
@Configuration(proxyBeanMethods = false)
static class GenericConverterConfiguration {
@Bean
@ConfigurationPropertiesBinding
static GenericConverter genericPersonConverter() {
return new GenericPersonConverter();
}
}
@Configuration(proxyBeanMethods = false)
static class FormatterConfiguration {
@Bean
@ConfigurationPropertiesBinding
static Formatter<Person> personFormatter() {
return new PersonFormatter();
}
}
@Configuration(proxyBeanMethods = false)
static class NonQualifiedGenericConverterConfiguration {
@Bean
GenericConverter genericPersonConverter() {
return new GenericPersonConverter();
}
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
static class GenericConfiguration {
@Bean
@ConfigurationProperties("foo")
AGenericClass<String> aBeanToBind() {
return new AGenericClass<>();
}
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(WithCustomValidatorProperties.class)
static class WithCustomValidatorConfiguration {
@Bean(name = EnableConfigurationProperties.VALIDATOR_BEAN_NAME)
CustomPropertiesValidator validator() {
return new CustomPropertiesValidator();
}
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(WithSetterThatThrowsValidationExceptionProperties.class)
static class WithUnsupportedCustomValidatorConfiguration {
@Bean(name = EnableConfigurationProperties.VALIDATOR_BEAN_NAME)
CustomPropertiesValidator validator() {
return new CustomPropertiesValidator();
}
}
static class AGenericClass<T> {
private @Nullable T bar;
@Nullable T getBar() {
return this.bar;
}
void setBar(@Nullable T bar) {
this.bar = bar;
}
}
static class PrototypeBean {
private @Nullable String one;
private @Nullable String two;
@Nullable String getOne() {
return this.one;
}
void setOne(@Nullable String one) {
this.one = one;
}
@Nullable String getTwo() {
return this.two;
}
void setTwo(@Nullable String two) {
this.two = two;
}
}
// Must be a raw type
@SuppressWarnings("rawtypes")
static class FactoryBeanTester implements FactoryBean, InitializingBean {
@Override
public Object getObject() {
return Object.class;
}
@Override
public @Nullable Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return true;
}
@Override
public void afterPropertiesSet() {
WithFactoryBeanConfiguration.factoryBeanInitialized = true;
}
}
@ConfigurationProperties
public static class BasicProperties {
private @Nullable String name;
private int @Nullable [] array;
private @Nullable List<Integer> list = new ArrayList<>();
private @Nullable Duration duration;
// No getter - you should be able to bind to a write-only bean
public void setName(@Nullable String name) {
// Must be public for XML
this.name = name;
}
void setArray(int... values) {
this.array = values;
}
int @Nullable [] getArray() {
return this.array;
}
@Nullable List<Integer> getList() {
return this.list;
}
void setList(@Nullable List<Integer> list) {
this.list = list;
}
@Nullable Duration getDuration() {
return this.duration;
}
void setDuration(@Nullable Duration duration) {
this.duration = duration;
}
}
@ConfigurationProperties
static class NestedProperties {
private @Nullable String name;
private final Nested nested = new Nested();
void setName(@Nullable String name) {
this.name = name;
}
Nested getNested() {
return this.nested;
}
static class Nested {
private @Nullable String name;
void setName(@Nullable String name) {
this.name = name;
}
}
}
@ConfigurationProperties(ignoreUnknownFields = false)
static class IgnoreUnknownFieldsFalseProperties extends BasicProperties {
}
@ConfigurationProperties(ignoreUnknownFields = false, ignoreInvalidFields = true)
static class IgnoreUnknownFieldsFalseIgnoreInvalidFieldsTrueProperties extends BasicProperties {
}
@EnableConfigurationProperties
@ConfigurationProperties(prefix = "com.example", ignoreInvalidFields = true)
static class IgnoreInvalidFieldsFalseProperties {
private long bar;
void setBar(long bar) {
this.bar = bar;
}
long getBar() {
return this.bar;
}
}
@ConfigurationProperties("spring.foo")
static class PrefixProperties extends BasicProperties {
}
@ConfigurationProperties("spring.bar")
static class AnotherPrefixProperties extends BasicProperties {
}
static class Jsr303Properties extends BasicProperties {
@NotEmpty
@SuppressWarnings("NullAway.Init")
private String description;
String getDescription() {
return this.description;
}
void setDescription(String description) {
this.description = description;
}
}
@ConfigurationProperties
@Validated
static class ValidatedJsr303Properties extends Jsr303Properties {
}
@ConfigurationProperties
static class NonValidatedJsr303Properties extends Jsr303Properties {
}
@EnableConfigurationProperties
@ConfigurationProperties
@Validated
static class ValidatedNestedJsr303Properties {
private final Jsr303Properties properties = new Jsr303Properties();
Jsr303Properties getProperties() {
return this.properties;
}
}
@EnableConfigurationProperties
@ConfigurationProperties
@Validated
static class ValidatedValidNestedJsr303Properties {
@Valid
private final Jsr303Properties properties = new Jsr303Properties();
Jsr303Properties getProperties() {
return this.properties;
}
}
static class AnnotationOnBaseClassProperties extends BasicProperties {
}
@ConfigurationProperties
static class WithoutAnnotationValueProperties {
private @Nullable String name;
void setName(@Nullable String name) {
this.name = name;
}
// No getter - you should be able to bind to a write-only bean
}
@EnableConfigurationProperties
@ConfigurationProperties
static class MapProperties {
private @Nullable Map<String, String> mymap;
void setMymap(@Nullable Map<String, String> mymap) {
this.mymap = mymap;
}
@Nullable Map<String, String> getMymap() {
return this.mymap;
}
}
@Component
static class BasicPropertiesConsumer {
@Autowired
private BasicProperties properties;
@PostConstruct
void init() {
assertThat(this.properties).isNotNull();
}
@Nullable String getName() {
return this.properties.name;
}
}
interface InterfaceForValidatedImplementation {
String getFoo();
}
@ConfigurationProperties("test")
@Validated
static class ValidatedImplementationProperties implements InterfaceForValidatedImplementation {
@NotNull
@SuppressWarnings("NullAway.Init")
private String foo;
@Override
public String getFoo() {
return this.foo;
}
void setFoo(String foo) {
this.foo = foo;
}
}
@ConfigurationProperties("test")
@Validated
static class WithPropertyPlaceholderValueProperties {
@Value("${default.value}")
private @Nullable String value;
void setValue(@Nullable String value) {
this.value = value;
}
@Nullable String getValue() {
return this.value;
}
}
@EnableConfigurationProperties
@ConfigurationProperties("test")
static class WithEnumProperties {
private @Nullable FooEnum theValue;
private @Nullable List<FooEnum> theValues;
void setTheValue(@Nullable FooEnum value) {
this.theValue = value;
}
@Nullable FooEnum getTheValue() {
return this.theValue;
}
@Nullable List<FooEnum> getTheValues() {
return this.theValues;
}
void setTheValues(@Nullable List<FooEnum> theValues) {
this.theValues = theValues;
}
}
enum FooEnum {
FOO, BAZ, BAR
}
@EnableConfigurationProperties
@ConfigurationProperties(prefix = "test", ignoreUnknownFields = false)
static class WithCharArrayProperties {
private char @Nullable [] chars;
char @Nullable [] getChars() {
return this.chars;
}
void setChars(char @Nullable [] chars) {
this.chars = chars;
}
}
@EnableConfigurationProperties
@ConfigurationProperties("test")
static class WithRelaxedNamesProperties {
private @Nullable String fooBar;
private @Nullable String barBAZ;
@Nullable String getFooBar() {
return this.fooBar;
}
void setFooBar(@Nullable String fooBar) {
this.fooBar = fooBar;
}
@Nullable String getBarBAZ() {
return this.barBAZ;
}
void setBarBAZ(@Nullable String barBAZ) {
this.barBAZ = barBAZ;
}
}
@Validated
@EnableConfigurationProperties
@ConfigurationProperties("test")
static class WithMapProperties {
private @Nullable Map<String, String> map;
@Nullable Map<String, String> getMap() {
return this.map;
}
void setMap(@Nullable Map<String, String> map) {
this.map = map;
}
}
@EnableConfigurationProperties
@ConfigurationProperties("test")
static class WithComplexMapProperties {
private @Nullable Map<String, Map<String, String>> map;
@Nullable Map<String, Map<String, String>> getMap() {
return this.map;
}
void setMap(@Nullable Map<String, Map<String, String>> map) {
this.map = map;
}
}
@EnableConfigurationProperties
@ConfigurationProperties("test")
static class WithIntegerMapProperties {
private @Nullable Map<String, Map<Integer, Foo>> map;
@Nullable Map<String, Map<Integer, Foo>> getMap() {
return this.map;
}
void setMap(@Nullable Map<String, Map<Integer, Foo>> map) {
this.map = map;
}
}
@EnableConfigurationProperties
@ConfigurationProperties(prefix = "com.example", ignoreUnknownFields = false)
static class SimplePrefixedProperties {
private int foo;
private @Nullable String bar;
@Nullable String getBar() {
return this.bar;
}
void setBar(@Nullable String bar) {
this.bar = bar;
}
int getFoo() {
return this.foo;
}
void setFoo(int foo) {
this.foo = foo;
}
}
@EnableConfigurationProperties
@ConfigurationProperties("test")
static class PersonProperties {
private @Nullable Person person;
@Nullable Person getPerson() {
return this.person;
}
void setPerson(@Nullable Person person) {
this.person = person;
}
}
@EnableConfigurationProperties
@ConfigurationProperties("test")
static class PersonAndAlienProperties {
private @Nullable Person person;
private @Nullable Alien alien;
@Nullable Person getPerson() {
return this.person;
}
void setPerson(@Nullable Person person) {
this.person = person;
}
@Nullable Alien getAlien() {
return this.alien;
}
void setAlien(@Nullable Alien alien) {
this.alien = alien;
}
}
@EnableConfigurationProperties
@ConfigurationProperties("test")
static class PersonAndAliensProperties {
private @Nullable Person person;
private @Nullable List<Alien> aliens;
@Nullable Person getPerson() {
return this.person;
}
void setPerson(@Nullable Person person) {
this.person = person;
}
@Nullable List<Alien> getAliens() {
return this.aliens;
}
void setAliens(@Nullable List<Alien> aliens) {
this.aliens = aliens;
}
}
@EnableConfigurationProperties
@ConfigurationProperties("sample")
static class MapWithNumericKeyProperties {
private final Map<String, BasicProperties> properties = new LinkedHashMap<>();
Map<String, BasicProperties> getProperties() {
return this.properties;
}
}
@EnableConfigurationProperties
@ConfigurationProperties
static class ValidatorProperties implements Validator {
private @Nullable String foo;
@Override
public boolean supports(Class<?> type) {
return type == ValidatorProperties.class;
}
@Override
public void validate(Object target, Errors errors) {
ValidationUtils.rejectIfEmpty(errors, "foo", "TEST1");
}
@Nullable String getFoo() {
return this.foo;
}
void setFoo(@Nullable String foo) {
this.foo = foo;
}
}
@EnableConfigurationProperties(ValidatorConstructorBoundProperties.class)
static class ValidatorConstructorBoundPropertiesConfiguration {
}
@ConfigurationProperties
static class ValidatorConstructorBoundProperties implements Validator {
private final String foo;
ValidatorConstructorBoundProperties(String foo) {
this.foo = foo;
}
@Override
public boolean supports(Class<?> type) {
return type == ValidatorConstructorBoundProperties.class;
}
@Override
public void validate(Object target, Errors errors) {
ValidationUtils.rejectIfEmpty(errors, "foo", "TEST1");
}
String getFoo() {
return this.foo;
}
}
@EnableConfigurationProperties
@ConfigurationProperties("test")
static class WithSetterThatThrowsValidationExceptionProperties {
private @Nullable String foo;
@Nullable String getFoo() {
return this.foo;
}
void setFoo(String foo) {
this.foo = foo;
if (!foo.equals("bar")) {
throw new IllegalArgumentException("Wrong value for foo");
}
}
}
@ConfigurationProperties("custom")
static class WithCustomValidatorProperties {
private @Nullable String foo;
@Nullable String getFoo() {
return this.foo;
}
void setFoo(@Nullable String foo) {
this.foo = foo;
}
}
@EnableConfigurationProperties
@ConfigurationProperties("test")
static class ListOfGenericClassProperties {
private @Nullable List<Class<? extends Throwable>> list;
@Nullable List<Class<? extends Throwable>> getList() {
return this.list;
}
void setList(@Nullable List<Class<? extends Throwable>> list) {
this.list = list;
}
}
@EnableConfigurationProperties
@ConfigurationProperties("test")
static class FileProperties {
private @Nullable File file;
@Nullable File getFile() {
return this.file;
}
void setFile(@Nullable File file) {
this.file = file;
}
}
@EnableConfigurationProperties
@ConfigurationProperties("test")
static class DataSizeProperties {
private @Nullable DataSize size;
@DataSizeUnit(DataUnit.KILOBYTES)
private @Nullable DataSize anotherSize;
@Nullable DataSize getSize() {
return this.size;
}
void setSize(@Nullable DataSize size) {
this.size = size;
}
@Nullable DataSize getAnotherSize() {
return this.anotherSize;
}
void setAnotherSize(@Nullable DataSize anotherSize) {
this.anotherSize = anotherSize;
}
}
@ConfigurationProperties("test")
static class OtherInjectedProperties {
final @Nullable DataSizeProperties dataSizeProperties;
OtherInjectedProperties(ObjectProvider<DataSizeProperties> dataSizeProperties) {
this.dataSizeProperties = dataSizeProperties.getIfUnique();
}
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(OtherInjectedProperties.class)
static class OtherInjectPropertiesConfiguration {
}
@ConfigurationProperties("test")
@Validated
static class ConstructorParameterProperties {
@NotEmpty
private final String foo;
private final int bar;
ConstructorParameterProperties(@DefaultValue("hello") String foo, int bar) {
this.foo = foo;
this.bar = bar;
}
String getFoo() {
return this.foo;
}
int getBar() {
return this.bar;
}
}
@ConfigurationProperties("test")
static class ConstructorParameterEmptyDefaultValueProperties {
private final Set<String> set;
private final Map<String, String> map;
private final int[] array;
private final Optional<String> optional;
ConstructorParameterEmptyDefaultValueProperties(@DefaultValue Set<String> set,
@DefaultValue Map<String, String> map, @DefaultValue int[] array,
@DefaultValue Optional<String> optional) {
this.set = set;
this.map = map;
this.array = array;
this.optional = optional;
}
Set<String> getSet() {
return this.set;
}
Map<String, String> getMap() {
return this.map;
}
int[] getArray() {
return this.array;
}
Optional<String> getOptional() {
return this.optional;
}
}
@ConfigurationProperties("test")
static class ConstructorParameterWithUnitProperties {
private final Duration duration;
private final DataSize size;
private final Period period;
@ConstructorBinding
ConstructorParameterWithUnitProperties(@DefaultValue("2") @DurationUnit(ChronoUnit.DAYS) Duration duration,
@DefaultValue("3") @DataSizeUnit(DataUnit.MEGABYTES) DataSize size,
@DefaultValue("4") @PeriodUnit(ChronoUnit.YEARS) Period period) {
this.size = size;
this.duration = duration;
this.period = period;
}
Duration getDuration() {
return this.duration;
}
DataSize getSize() {
return this.size;
}
Period getPeriod() {
return this.period;
}
}
@ConfigurationProperties("test")
static class ConstructorParameterWithFormatProperties {
private final Duration duration;
private final Period period;
ConstructorParameterWithFormatProperties(
@DefaultValue("2d") @DurationFormat(DurationStyle.SIMPLE) Duration duration,
@DefaultValue("3y") @PeriodFormat(PeriodStyle.SIMPLE) Period period) {
this.duration = duration;
this.period = period;
}
Duration getDuration() {
return this.duration;
}
Period getPeriod() {
return this.period;
}
}
@ConfigurationProperties("test")
@Validated
static class ConstructorParameterValidatedProperties {
@NotEmpty
private final String foo;
ConstructorParameterValidatedProperties(String foo) {
this.foo = foo;
}
String getFoo() {
return this.foo;
}
}
@EnableConfigurationProperties(ConstructorParameterProperties.class)
static class ConstructorParameterConfiguration {
}
@EnableConfigurationProperties(ConstructorParameterEmptyDefaultValueProperties.class)
static class ConstructorParameterEmptyDefaultValueConfiguration {
}
@EnableConfigurationProperties(ConstructorParameterWithUnitProperties.class)
static class ConstructorParameterWithUnitConfiguration {
}
@EnableConfigurationProperties(ConstructorParameterWithFormatProperties.class)
static class ConstructorParameterWithFormatConfiguration {
}
@EnableConfigurationProperties(ConstructorParameterValidatedProperties.class)
static class ConstructorParameterValidationConfiguration {
}
static class CustomPropertiesValidator implements Validator {
@Override
public boolean supports(Class<?> type) {
return type == WithCustomValidatorProperties.class;
}
@Override
public void validate(Object target, Errors errors) {
ValidationUtils.rejectIfEmpty(errors, "foo", "TEST1");
}
}
static class PersonConverter implements Converter<String, Person> {
@Override
public Person convert(String source) {
String[] content = StringUtils.split(source, " ");
assertThat(content).isNotNull();
return new Person(content[0], content[1]);
}
}
static class AlienConverter implements Converter<String, Alien> {
@Override
public Alien convert(String source) {
return new Alien(new StringBuilder(source).reverse().toString());
}
}
static class GenericPersonConverter implements GenericConverter {
@Override
public Set<ConvertiblePair> getConvertibleTypes() {
return Collections.singleton(new ConvertiblePair(String.class, Person.class));
}
@Override
public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
String[] content = StringUtils.split((String) source, " ");
assertThat(content).isNotNull();
return new Person(content[0], content[1]);
}
}
static class PersonFormatter implements Formatter<Person> {
@Override
public String print(Person person, Locale locale) {
return person.getFirstName() + " " + person.getLastName();
}
@Override
public Person parse(String text, Locale locale) throws ParseException {
String[] content = text.split(" ");
return new Person(content[0], content[1]);
}
}
static class PersonPropertyEditor extends PropertyEditorSupport {
@Override
public void setAsText(String text) {
String[] content = text.split(",");
setValue(new Person(content[1], content[0]));
}
}
static class Person {
private final String firstName;
private final String lastName;
Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
String getFirstName() {
return this.firstName;
}
String getLastName() {
return this.lastName;
}
}
static class Alien {
private final String name;
Alien(String name) {
this.name = name;
}
String getName() {
return this.name;
}
}
static class Foo {
private @Nullable String a;
private int b;
@Nullable String getA() {
return this.a;
}
void setA(@Nullable String a) {
this.a = a;
}
int getB() {
return this.b;
}
void setB(int b) {
this.b = b;
}
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(NestedConstructorProperties.class)
static class NestedConstructorPropertiesConfiguration {
}
@ConfigurationProperties("test")
static class NestedConstructorProperties {
private final String name;
private final Nested nested;
NestedConstructorProperties(String name, Nested nested) {
this.name = name;
this.nested = nested;
}
String getName() {
return this.name;
}
Nested getNested() {
return this.nested;
}
static class Nested {
private final int age;
@ConstructorBinding
Nested(int age) {
this.age = age;
}
int getAge() {
return this.age;
}
}
}
@ConfigurationProperties("test")
static class NestedMultipleConstructorProperties {
private final String name;
private final Nested nested;
NestedMultipleConstructorProperties(String name, Nested nested) {
this.name = name;
this.nested = nested;
}
String getName() {
return this.name;
}
Nested getNested() {
return this.nested;
}
static class Nested {
private int age;
Nested(String property) {
}
@ConstructorBinding
Nested(int age) {
this.age = age;
}
int getAge() {
return this.age;
}
}
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(NestedMultipleConstructorProperties.class)
static class NestedMultipleConstructorsConfiguration {
}
@ConfigurationProperties("test")
static class ConstructorBindingWithOuterClassConstructorBoundProperties {
private final Nested nested;
ConstructorBindingWithOuterClassConstructorBoundProperties(Nested nested) {
this.nested = nested;
}
Nested getNested() {
return this.nested;
}
static class Nested {
private @Nullable Outer outer;
@Nullable Outer getOuter() {
return this.outer;
}
void setOuter(@Nullable Outer nested) {
this.outer = nested;
}
}
}
@ConfigurationProperties("test")
static class ConstructorBindingWithOuterClassConstructorBoundAndNestedAutowired {
private final Nested nested;
ConstructorBindingWithOuterClassConstructorBoundAndNestedAutowired(Nested nested) {
this.nested = nested;
}
Nested getNested() {
return this.nested;
}
static class Nested {
private final int age;
@Autowired
Nested(int age) {
this.age = age;
}
int getAge() {
return this.age;
}
}
}
static class Outer {
private final int age;
Outer(int age) {
this.age = age;
}
int getAge() {
return this.age;
}
}
@EnableConfigurationProperties(ConstructorBindingWithOuterClassConstructorBoundProperties.class)
static class ConstructorBindingWithOuterClassConstructorBoundConfiguration {
}
@EnableConfigurationProperties(ConstructorBindingWithOuterClassConstructorBoundAndNestedAutowired.class)
static class ConstructorBindingWithOuterClassConstructorBoundAndNestedAutowiredConfiguration {
}
@ConfigurationProperties("test")
static class MultiConstructorConfigurationListProperties {
private final List<MultiConstructorConfigurationProperties> nested = new ArrayList<>();
List<MultiConstructorConfigurationProperties> getNested() {
return this.nested;
}
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(MultiConstructorConfigurationListProperties.class)
static class MultiConstructorConfigurationPropertiesConfiguration {
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(JavaBeanNestedConstructorBindingProperties.class)
static class JavaBeanNestedConstructorBindingPropertiesConfiguration {
}
@ConfigurationProperties("test")
static class JavaBeanNestedConstructorBindingProperties {
private @Nullable Nested nested;
@Nullable Nested getNested() {
return this.nested;
}
void setNested(@Nullable Nested nested) {
this.nested = nested;
}
static final class Nested {
private final int age;
@ConstructorBinding
private Nested(int age) {
this.age = age;
}
int getAge() {
return this.age;
}
}
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(JavaBeanNonDefaultConstructorProperties.class)
static class JavaBeanNonDefaultConstructorPropertiesConfiguration {
}
@ConfigurationProperties("test")
static class JavaBeanNonDefaultConstructorProperties {
private @Nullable Nested nested;
@Nullable Nested getNested() {
return this.nested;
}
void setNested(@Nullable Nested nested) {
this.nested = nested;
}
static final class Nested {
private int age;
private Nested() {
}
private Nested(int age) {
this.age = age;
}
int getAge() {
return this.age;
}
void setAge(int age) {
this.age = age + 5;
}
}
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(SyntheticNestedConstructorProperties.class)
static class SyntheticConstructorPropertiesConfiguration {
}
@ConfigurationProperties("test")
static class SyntheticNestedConstructorProperties {
private final Nested nested;
SyntheticNestedConstructorProperties(Nested nested) {
this.nested = nested;
}
Nested getNested() {
return this.nested;
}
static final class Nested {
private int age;
private Nested() {
}
int getAge() {
return this.age;
}
void setAge(int age) {
this.age = age;
}
static class AnotherNested {
private final Nested nested;
AnotherNested(String name) {
this.nested = new Nested();
}
Nested getNested() {
return this.nested;
}
}
}
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(DeducedNestedConstructorProperties.class)
static class DeducedNestedConstructorPropertiesConfiguration {
}
@ConfigurationProperties("test")
static class DeducedNestedConstructorProperties {
private final String name;
private final Nested nested;
DeducedNestedConstructorProperties(String name, Nested nested) {
this.name = name;
this.nested = nested;
}
String getName() {
return this.name;
}
Nested getNested() {
return this.nested;
}
static class Nested {
private final int age;
Nested(int age) {
this.age = age;
}
int getAge() {
return this.age;
}
}
}
@Configuration
@EnableConfigurationProperties(WithPublicStringConstructorProperties.class)
static class WithPublicStringConstructorPropertiesConfiguration {
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(WithCustomConverterAndObjectToObjectMethodProperties.class)
static class WithCustomConverterAndObjectToObjectMethodConfiguration {
@Bean
@ConfigurationPropertiesBinding
static WithObjectToObjectMethodConverter withObjectToObjectMethodConverter() {
return new WithObjectToObjectMethodConverter();
}
}
@ConfigurationProperties("test")
static class WithCustomConverterAndObjectToObjectMethodProperties {
private @Nullable WithPublicObjectToObjectMethod item;
@Nullable WithPublicObjectToObjectMethod getItem() {
return this.item;
}
void setItem(@Nullable WithPublicObjectToObjectMethod item) {
this.item = item;
}
}
static class WithObjectToObjectMethodConverter implements Converter<String, WithPublicObjectToObjectMethod> {
@Override
public WithPublicObjectToObjectMethod convert(String source) {
return new WithPublicObjectToObjectMethod(source);
}
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
static class ConstructorUsedInBeanMethodConfiguration {
@Bean
@ConfigurationProperties("test")
ConstructorUsedDirectly constructorUsedInBeanMethod() {
return new ConstructorUsedDirectly("bean-method-1", "bean-method-2");
}
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(ConstructorUsedInNestedProperty.class)
static class ConstructorUsedInNestedPropertyConfiguration {
}
@ConfigurationProperties("test")
static class ConstructorUsedInNestedProperty {
@NestedConfigurationProperty
private ConstructorUsedDirectly nested = new ConstructorUsedDirectly("nested-1", "nested-2");
ConstructorUsedDirectly getNested() {
return this.nested;
}
void setNested(ConstructorUsedDirectly nested) {
this.nested = nested;
}
}
static class ConstructorUsedDirectly {
private String one;
private String two;
ConstructorUsedDirectly(String one, String two) {
this.one = one;
this.two = two;
}
String getOne() {
return this.one;
}
void setOne(String one) {
this.one = one;
}
String getTwo() {
return this.two;
}
void setTwo(String two) {
this.two = two;
}
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(NestedRecordInstanceProperties.class)
static class NestedRecordInstancePropertiesConfiguration {
}
@ConfigurationProperties("test")
static class NestedRecordInstanceProperties {
@NestedConfigurationProperty
private NestedRecord nested = new NestedRecord("unnamed");
NestedRecord getNested() {
return this.nested;
}
void setNested(NestedRecord nestedRecord) {
this.nested = nestedRecord;
}
}
record NestedRecord(String name) {
}
@EnableConfigurationProperties
@Import(PotentiallyConstructorBoundProperties.class)
static class PotentiallyConstructorBoundPropertiesImporter {
@Bean
String notAProperty() {
return "notAProperty";
}
}
@ConfigurationProperties("test")
static class PotentiallyConstructorBoundProperties {
private @Nullable String prop;
PotentiallyConstructorBoundProperties(String notAProperty) {
}
@Nullable String getProp() {
return this.prop;
}
void setProp(@Nullable String prop) {
this.prop = prop;
}
}
@EnableConfigurationProperties(ResourceArrayProperties.class)
static class ResourceArrayPropertiesConfiguration {
}
@ConfigurationProperties("test")
static class ResourceArrayProperties {
private Resource @Nullable [] resources;
Resource @Nullable [] getResources() {
return this.resources;
}
void setResources(Resource @Nullable [] resources) {
this.resources = resources;
}
}
@EnableConfigurationProperties(ResourceCollectionProperties.class)
static class ResourceCollectionPropertiesConfiguration {
}
@ConfigurationProperties("test")
static class ResourceCollectionProperties {
private @Nullable Collection<Resource> resources;
@Nullable Collection<Resource> getResources() {
return this.resources;
}
void setResources(@Nullable Collection<Resource> resources) {
this.resources = resources;
}
}
@EnableConfigurationProperties(ConstructorBoundCustomListProperties.class)
static class ConstructorBoundCustomListPropertiesConfiguration {
@Bean
@ConfigurationPropertiesBinding
static Converter<ArrayList<?>, CustomList<?>> arrayListToCustomList() {
return new Converter<>() {
@Override
public CustomList<?> convert(ArrayList<?> source) {
return new CustomList<>(source);
}
};
}
}
@ConfigurationProperties("test")
static class ConstructorBoundCustomListProperties {
private final CustomList<String> values;
ConstructorBoundCustomListProperties(CustomList<String> values) {
this.values = values;
}
CustomList<String> getValues() {
return this.values;
}
}
@EnableConfigurationProperties(SetterBoundCustomListProperties.class)
static class SetterBoundCustomListPropertiesConfiguration {
@Bean
@ConfigurationPropertiesBinding
static Converter<ArrayList<?>, CustomList<?>> arrayListToCustomList() {
return new Converter<>() {
@Override
public CustomList<?> convert(ArrayList<?> source) {
return new CustomList<>(source);
}
};
}
}
@ConfigurationProperties("test")
static class SetterBoundCustomListProperties {
private @Nullable CustomList<String> values;
@Nullable CustomList<String> getValues() {
return this.values;
}
void setValues(@Nullable CustomList<String> values) {
this.values = values;
}
}
static final class CustomList<E> extends ArrayList<E> {
CustomList(List<E> delegate) {
super(delegate);
}
}
}
Domain
Source
Analyze Your Own Codebase
Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.
Try Supermodel Free