diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/client/ExampleProperties.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/client/ExampleProperties.java new file mode 100644 index 00000000000..7b25bcba79f --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/client/ExampleProperties.java @@ -0,0 +1,41 @@ +/* + * Copyright 2012-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.test.autoconfigure.web.client; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.bind.DefaultValue; + +/** + * Example {@link ConfigurationProperties} used to test the use of configuration + * properties scan with sliced test. + * + * @author Stephane Nicoll + */ +@ConfigurationProperties("example") +public class ExampleProperties { + + private final String name; + + public ExampleProperties(@DefaultValue("test") String name) { + this.name = name; + } + + public String getName() { + return this.name; + } + +} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTestNoComponentIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTestNoComponentIntegrationTests.java index 5c4b7834b35..c44fbbee7e0 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTestNoComponentIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTestNoComponentIntegrationTests.java @@ -53,6 +53,12 @@ class RestClientTestNoComponentIntegrationTests { .isThrownBy(() -> this.applicationContext.getBean(ExampleRestClient.class)); } + @Test + void examplePropertiesIsNotInjected() { + assertThatExceptionOfType(NoSuchBeanDefinitionException.class) + .isThrownBy(() -> this.applicationContext.getBean(ExampleProperties.class)); + } + @Test void manuallyCreateBean() { ExampleRestClient client = new ExampleRestClient(this.restTemplateBuilder); diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTestWithConfigurationPropertiesIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTestWithConfigurationPropertiesIntegrationTests.java new file mode 100644 index 00000000000..907d7ae7c6a --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTestWithConfigurationPropertiesIntegrationTests.java @@ -0,0 +1,46 @@ +/* + * Copyright 2012-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.test.autoconfigure.web.client; + +import org.junit.jupiter.api.Test; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.ApplicationContext; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link RestClientTest @RestClientTest} with a {@link ConfigurationProperties} + * annotated type. + * + * @author Stephane Nicoll + */ +@RestClientTest(components = ExampleProperties.class, properties = "example.name=Hello") +class RestClientTestWithConfigurationPropertiesIntegrationTests { + + @Autowired + private ApplicationContext applicationContext; + + @Test + void configurationPropertiesCanBeAddedAsComponent() { + assertThat(this.applicationContext.getBeansOfType(ExampleProperties.class).keySet()) + .containsOnly("example-org.springframework.boot.test.autoconfigure.web.client.ExampleProperties"); + assertThat(this.applicationContext.getBean(ExampleProperties.class).getName()).isEqualTo("Hello"); + } + +} diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesScanRegistrar.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesScanRegistrar.java index 8a3dcb95766..6f58ef3b137 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesScanRegistrar.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesScanRegistrar.java @@ -22,6 +22,7 @@ import java.util.Set; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.boot.context.TypeExcludeFilter; import org.springframework.context.EnvironmentAware; import org.springframework.context.ResourceLoaderAware; import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; @@ -82,6 +83,9 @@ class ConfigurationPropertiesScanRegistrar scanner.setEnvironment(this.environment); scanner.setResourceLoader(this.resourceLoader); scanner.addIncludeFilter(new AnnotationTypeFilter(ConfigurationProperties.class)); + TypeExcludeFilter typeExcludeFilter = new TypeExcludeFilter(); + typeExcludeFilter.setBeanFactory(beanFactory); + scanner.addExcludeFilter(typeExcludeFilter); for (String basePackage : packages) { if (StringUtils.hasText(basePackage)) { scan(beanFactory, registry, scanner, basePackage); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesScanRegistrarTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesScanRegistrarTests.java index be4a90aebcb..8875e572b15 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesScanRegistrarTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesScanRegistrarTests.java @@ -87,10 +87,13 @@ class ConfigurationPropertiesScanRegistrarTests { .isFalse(); BeanDefinition aDefinition = beanFactory.getBeanDefinition( "a-org.springframework.boot.context.properties.scan.valid.a.AScanConfiguration$AProperties"); - BeanDefinition bDefinition = beanFactory.getBeanDefinition( - "b-org.springframework.boot.context.properties.scan.valid.b.BScanConfiguration$BProperties"); + BeanDefinition bFirstDefinition = beanFactory.getBeanDefinition( + "b.first-org.springframework.boot.context.properties.scan.valid.b.BScanConfiguration$BFirstProperties"); + BeanDefinition bSecondDefinition = beanFactory.getBeanDefinition( + "b.second-org.springframework.boot.context.properties.scan.valid.b.BScanConfiguration$BSecondProperties"); assertThat(aDefinition).isExactlyInstanceOf(GenericBeanDefinition.class); - assertThat(bDefinition).isExactlyInstanceOf(GenericBeanDefinition.class); + assertThat(bFirstDefinition).isExactlyInstanceOf(GenericBeanDefinition.class); + assertThat(bSecondDefinition).isExactlyInstanceOf(GenericBeanDefinition.class); } @Test diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesScanTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesScanTests.java index 1ecccfc97ca..182ae22de5f 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesScanTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesScanTests.java @@ -16,14 +16,23 @@ package org.springframework.boot.context.properties; +import java.io.IOException; +import java.util.Objects; + import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.boot.context.TypeExcludeFilter; import org.springframework.boot.context.properties.scan.valid.a.AScanConfiguration; +import org.springframework.boot.context.properties.scan.valid.b.BScanConfiguration.BFirstProperties; +import org.springframework.boot.context.properties.scan.valid.b.BScanConfiguration.BProperties; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.core.io.ByteArrayResource; import org.springframework.core.io.DefaultResourceLoader; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.core.type.filter.AssignableTypeFilter; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.BDDMockito.given; @@ -89,6 +98,23 @@ class ConfigurationPropertiesScanTests { .isFalse(); } + @Test + void scanImportBeanRegistrarShouldUsePackageName() { + load(TestAnotherPackageConfiguration.class); + assertThat(this.context.getBeanNamesForType(BProperties.class)).containsOnly( + "b.first-org.springframework.boot.context.properties.scan.valid.b.BScanConfiguration$BFirstProperties", + "b.second-org.springframework.boot.context.properties.scan.valid.b.BScanConfiguration$BSecondProperties"); + } + + @Test + void scanImportBeanRegistrarShouldApplyTypeExcludeFilter() { + this.context.getBeanFactory().registerSingleton("filter", new ConfigurationPropertiesTestTypeExcludeFilter()); + this.context.register(TestAnotherPackageConfiguration.class); + this.context.refresh(); + assertThat(this.context.getBeanNamesForType(BProperties.class)).containsOnly( + "b.first-org.springframework.boot.context.properties.scan.valid.b.BScanConfiguration$BFirstProperties"); + } + private void load(Class... classes) { this.context.register(classes); this.context.refresh(); @@ -99,4 +125,30 @@ class ConfigurationPropertiesScanTests { } + @ConfigurationPropertiesScan(basePackages = "org.springframework.boot.context.properties.scan.valid.b") + static class TestAnotherPackageConfiguration { + + } + + static class ConfigurationPropertiesTestTypeExcludeFilter extends TypeExcludeFilter { + + @Override + public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) + throws IOException { + AssignableTypeFilter typeFilter = new AssignableTypeFilter(BFirstProperties.class); + return !typeFilter.match(metadataReader, metadataReaderFactory); + } + + @Override + public boolean equals(Object o) { + return (this == o); + } + + @Override + public int hashCode() { + return Objects.hash(42); + } + + } + } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/scan/valid/b/BScanConfiguration.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/scan/valid/b/BScanConfiguration.java index 98e25c9d22a..6e671848175 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/scan/valid/b/BScanConfiguration.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/scan/valid/b/BScanConfiguration.java @@ -19,11 +19,21 @@ import org.springframework.boot.context.properties.ConfigurationProperties; /** * @author Madhura Bhave + * @author Stephane Nicoll */ public class BScanConfiguration { - @ConfigurationProperties(prefix = "b") - static class BProperties { + public interface BProperties { + + } + + @ConfigurationProperties(prefix = "b.first") + public static class BFirstProperties implements BProperties { + + } + + @ConfigurationProperties(prefix = "b.second") + public static class BSecondProperties implements BProperties { }