mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-08-29 03:06:45 +08:00
Revert "Support constructor binding on 3rd party classes"
This commit reverts the support of constructor binding on 3rd party classes using @ImportConfigurationPropertiesBean See gh-23172 Closes gh-23593
This commit is contained in:
parent
2595258494
commit
1296b4dfe6
@ -1242,7 +1242,7 @@ Spring Boot provides infrastructure to bind `@ConfigurationProperties` types and
|
||||
You can either enable configuration properties on a class-by-class basis or enable configuration property scanning that works in a similar manner to component scanning.
|
||||
|
||||
Sometimes, classes annotated with `@ConfigurationProperties` might not be suitable for scanning, for example, if you're developing your own auto-configuration or you want to enable them conditionally.
|
||||
In these cases, specify the list of types to process using the `@EnableConfigurationProperties` or `@ImportAsConfigurationPropertiesBean` annotations.
|
||||
In these cases, specify the list of types to process using the `@EnableConfigurationProperties` annotation.
|
||||
This can be done on any `@Configuration` class, as shown in the following example:
|
||||
|
||||
[source,java,indent=0]
|
||||
@ -1268,7 +1268,7 @@ If you want to define specific packages to scan, you can do so as shown in the f
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
When the `@ConfigurationProperties` bean is registered using configuration property scanning or via `@EnableConfigurationProperties` or `@ImportAsConfigurationPropertiesBean`, the bean has a conventional name: `<prefix>-<fqn>`, where `<prefix>` is the environment key prefix specified in the `@ConfigurationProperties` annotation and `<fqn>` is the fully qualified name of the bean.
|
||||
When the `@ConfigurationProperties` bean is registered using configuration property scanning or via `@EnableConfigurationProperties`, the bean has a conventional name: `<prefix>-<fqn>`, where `<prefix>` is the environment key prefix specified in the `@ConfigurationProperties` annotation and `<fqn>` is the fully qualified name of the bean.
|
||||
If the annotation does not provide any prefix, only the fully qualified name of the bean is used.
|
||||
|
||||
The bean name in the example above is `acme-com.example.AcmeProperties`.
|
||||
@ -1336,26 +1336,12 @@ To configure a bean from the `Environment` properties, add `@ConfigurationProper
|
||||
----
|
||||
@ConfigurationProperties(prefix = "another")
|
||||
@Bean
|
||||
public ExampleItem exampleItem() {
|
||||
public AnotherComponent anotherComponent() {
|
||||
...
|
||||
}
|
||||
----
|
||||
|
||||
Any JavaBean property defined with the `another` prefix is mapped onto that `ExampleItem` bean in manner similar to the preceding `AcmeProperties` example.
|
||||
|
||||
If you want to use constructor binding with a third-party class, you can't use a `@Bean` method since Spring will need to create the object instance.
|
||||
For those situations, you can use an `@ImportAsConfigurationPropertiesBean` annotation on your `@Configuration` or `@SpringBootApplication` class.
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@SpringBootApplication
|
||||
@ImportAsConfigurationPropertiesBean(type = ExampleItem.class, prefix = "another")
|
||||
public class MyApp {
|
||||
...
|
||||
}
|
||||
----
|
||||
|
||||
TIP: `@ImportAsConfigurationPropertiesBean` also works for JavaBean bindings as long as the type has a single no-arg constructor
|
||||
Any JavaBean property defined with the `another` prefix is mapped onto that `AnotherComponent` bean in manner similar to the preceding `AcmeProperties` example.
|
||||
|
||||
|
||||
|
||||
|
@ -22,7 +22,6 @@ import java.io.StringWriter;
|
||||
import java.time.Duration;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@ -41,7 +40,6 @@ import javax.lang.model.element.Modifier;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.element.VariableElement;
|
||||
import javax.lang.model.type.TypeKind;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
import javax.lang.model.util.ElementFilter;
|
||||
import javax.tools.Diagnostic.Kind;
|
||||
|
||||
@ -82,10 +80,6 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor
|
||||
|
||||
static final String NAME_ANNOTATION = "org.springframework.boot.context.properties.bind.Name";
|
||||
|
||||
static final String IMPORT_AS_CONFIGURATION_PROPERTIES_BEAN_ANNOATION = "org.springframework.boot.context.properties.ImportAsConfigurationPropertiesBean";
|
||||
|
||||
static final String IMPORT_AS_CONFIGURATION_PROPERTIES_BEANS_ANNOATION = "org.springframework.boot.context.properties.ImportAsConfigurationPropertiesBeans";
|
||||
|
||||
private static final Set<String> SUPPORTED_OPTIONS = Collections
|
||||
.unmodifiableSet(Collections.singleton(ADDITIONAL_METADATA_LOCATIONS_OPTION));
|
||||
|
||||
@ -127,14 +121,6 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor
|
||||
return NAME_ANNOTATION;
|
||||
}
|
||||
|
||||
protected String importAsConfigurationPropertiesBeanAnnotation() {
|
||||
return IMPORT_AS_CONFIGURATION_PROPERTIES_BEAN_ANNOATION;
|
||||
}
|
||||
|
||||
protected String importAsConfigurationPropertiesBeansAnnotation() {
|
||||
return IMPORT_AS_CONFIGURATION_PROPERTIES_BEANS_ANNOATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceVersion getSupportedSourceVersion() {
|
||||
return SourceVersion.latestSupported();
|
||||
@ -153,16 +139,22 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor
|
||||
this.metadataEnv = new MetadataGenerationEnvironment(env, configurationPropertiesAnnotation(),
|
||||
nestedConfigurationPropertyAnnotation(), deprecatedConfigurationPropertyAnnotation(),
|
||||
constructorBindingAnnotation(), defaultValueAnnotation(), endpointAnnotation(),
|
||||
readOperationAnnotation(), nameAnnotation(), importAsConfigurationPropertiesBeanAnnotation(),
|
||||
importAsConfigurationPropertiesBeansAnnotation());
|
||||
readOperationAnnotation(), nameAnnotation());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
||||
this.metadataCollector.processing(roundEnv);
|
||||
processConfigurationProperties(roundEnv);
|
||||
processEndpoint(roundEnv);
|
||||
processImportAsConfigurationProperties(roundEnv);
|
||||
TypeElement annotationType = this.metadataEnv.getConfigurationPropertiesAnnotationElement();
|
||||
if (annotationType != null) { // Is @ConfigurationProperties available
|
||||
for (Element element : roundEnv.getElementsAnnotatedWith(annotationType)) {
|
||||
processElement(element);
|
||||
}
|
||||
}
|
||||
TypeElement endpointType = this.metadataEnv.getEndpointAnnotationElement();
|
||||
if (endpointType != null) { // Is @Endpoint available
|
||||
getElementsAnnotatedOrMetaAnnotatedWith(roundEnv, endpointType).forEach(this::processEndpoint);
|
||||
}
|
||||
if (roundEnv.processingOver()) {
|
||||
try {
|
||||
writeMetaData();
|
||||
@ -174,40 +166,6 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor
|
||||
return false;
|
||||
}
|
||||
|
||||
private void processConfigurationProperties(RoundEnvironment roundEnv) {
|
||||
TypeElement annotationType = this.metadataEnv.getConfigurationPropertiesAnnotationElement();
|
||||
if (annotationType != null) {
|
||||
for (Element element : roundEnv.getElementsAnnotatedWith(annotationType)) {
|
||||
processElement(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processEndpoint(RoundEnvironment roundEnv) {
|
||||
TypeElement endpointType = this.metadataEnv.getEndpointAnnotationElement();
|
||||
if (endpointType != null) {
|
||||
getElementsAnnotatedOrMetaAnnotatedWith(roundEnv, endpointType).forEach(this::processEndpoint);
|
||||
}
|
||||
}
|
||||
|
||||
private void processImportAsConfigurationProperties(RoundEnvironment roundEnv) {
|
||||
TypeElement importAsConfigurationPropertiesBeanType = this.metadataEnv
|
||||
.getImportAsConfigurationPropertiesBeansAnnotation();
|
||||
TypeElement importAsConfigurationPropertiesBeansType = this.metadataEnv
|
||||
.getImportAsConfigurationPropertiesBeansAnnotationElement();
|
||||
if (importAsConfigurationPropertiesBeanType == null && importAsConfigurationPropertiesBeansType == null) {
|
||||
return;
|
||||
}
|
||||
Set<Element> elements = new LinkedHashSet<>();
|
||||
if (importAsConfigurationPropertiesBeanType != null) {
|
||||
elements.addAll(roundEnv.getElementsAnnotatedWith(importAsConfigurationPropertiesBeanType));
|
||||
}
|
||||
if (importAsConfigurationPropertiesBeansType != null) {
|
||||
elements.addAll(roundEnv.getElementsAnnotatedWith(importAsConfigurationPropertiesBeansType));
|
||||
}
|
||||
elements.forEach(this::processImportAsConfigurationPropertiesBean);
|
||||
}
|
||||
|
||||
private Map<Element, List<Element>> getElementsAnnotatedOrMetaAnnotatedWith(RoundEnvironment roundEnv,
|
||||
TypeElement annotation) {
|
||||
Map<Element, List<Element>> result = new LinkedHashMap<>();
|
||||
@ -226,7 +184,7 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor
|
||||
if (annotation != null) {
|
||||
String prefix = getPrefix(annotation);
|
||||
if (element instanceof TypeElement) {
|
||||
processAnnotatedTypeElement(prefix, (TypeElement) element, false, new Stack<>());
|
||||
processAnnotatedTypeElement(prefix, (TypeElement) element, new Stack<>());
|
||||
}
|
||||
else if (element instanceof ExecutableElement) {
|
||||
processExecutableElement(prefix, (ExecutableElement) element, new Stack<>());
|
||||
@ -238,11 +196,10 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor
|
||||
}
|
||||
}
|
||||
|
||||
private void processAnnotatedTypeElement(String prefix, TypeElement element, boolean fromImport,
|
||||
Stack<TypeElement> seen) {
|
||||
private void processAnnotatedTypeElement(String prefix, TypeElement element, Stack<TypeElement> seen) {
|
||||
String type = this.metadataEnv.getTypeUtils().getQualifiedName(element);
|
||||
this.metadataCollector.add(ItemMetadata.newGroup(prefix, type, type, null));
|
||||
processTypeElement(prefix, element, fromImport, null, seen);
|
||||
processTypeElement(prefix, element, null, seen);
|
||||
}
|
||||
|
||||
private void processExecutableElement(String prefix, ExecutableElement element, Stack<TypeElement> seen) {
|
||||
@ -260,26 +217,25 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor
|
||||
}
|
||||
else {
|
||||
this.metadataCollector.add(group);
|
||||
processTypeElement(prefix, (TypeElement) returns, false, element, seen);
|
||||
processTypeElement(prefix, (TypeElement) returns, element, seen);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processTypeElement(String prefix, TypeElement element, boolean fromImport, ExecutableElement source,
|
||||
private void processTypeElement(String prefix, TypeElement element, ExecutableElement source,
|
||||
Stack<TypeElement> seen) {
|
||||
if (!seen.contains(element)) {
|
||||
seen.push(element);
|
||||
new PropertyDescriptorResolver(this.metadataEnv).resolve(element, fromImport, source)
|
||||
.forEach((descriptor) -> {
|
||||
this.metadataCollector.add(descriptor.resolveItemMetadata(prefix, this.metadataEnv));
|
||||
if (descriptor.isNested(this.metadataEnv)) {
|
||||
TypeElement nestedTypeElement = (TypeElement) this.metadataEnv.getTypeUtils()
|
||||
.asElement(descriptor.getType());
|
||||
String nestedPrefix = ConfigurationMetadata.nestedPrefix(prefix, descriptor.getName());
|
||||
processTypeElement(nestedPrefix, nestedTypeElement, false, source, seen);
|
||||
}
|
||||
});
|
||||
new PropertyDescriptorResolver(this.metadataEnv).resolve(element, source).forEach((descriptor) -> {
|
||||
this.metadataCollector.add(descriptor.resolveItemMetadata(prefix, this.metadataEnv));
|
||||
if (descriptor.isNested(this.metadataEnv)) {
|
||||
TypeElement nestedTypeElement = (TypeElement) this.metadataEnv.getTypeUtils()
|
||||
.asElement(descriptor.getType());
|
||||
String nestedPrefix = ConfigurationMetadata.nestedPrefix(prefix, descriptor.getName());
|
||||
processTypeElement(nestedPrefix, nestedTypeElement, source, seen);
|
||||
}
|
||||
});
|
||||
seen.pop();
|
||||
}
|
||||
}
|
||||
@ -316,31 +272,6 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor
|
||||
}
|
||||
}
|
||||
|
||||
private void processImportAsConfigurationPropertiesBean(Element element) {
|
||||
this.metadataEnv.getImportAsConfigurationPropertiesBeanAnnotations(element)
|
||||
.forEach(this::processImportAsConfigurationPropertiesBean);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void processImportAsConfigurationPropertiesBean(AnnotationMirror annotation) {
|
||||
String prefix = getPrefix(annotation);
|
||||
processImportAsConfigurationPropertiesBeanTypes(prefix,
|
||||
(List<TypeMirror>) this.metadataEnv.getAnnotationElementValues(annotation).get("type"));
|
||||
processImportAsConfigurationPropertiesBeanTypes(prefix,
|
||||
(List<TypeMirror>) this.metadataEnv.getAnnotationElementValues(annotation).get("value"));
|
||||
}
|
||||
|
||||
private void processImportAsConfigurationPropertiesBeanTypes(String prefix, List<TypeMirror> types) {
|
||||
if (types != null) {
|
||||
for (TypeMirror type : types) {
|
||||
Element element = this.metadataEnv.getTypeUtils().asElement(type);
|
||||
AnnotationMirror annotation = this.metadataEnv.getConfigurationPropertiesAnnotation(element);
|
||||
prefix = (annotation != null) ? getPrefix(annotation) : prefix;
|
||||
processAnnotatedTypeElement(prefix, (TypeElement) element, true, new Stack<>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasMainReadOperation(TypeElement element) {
|
||||
for (ExecutableElement method : ElementFilter.methodsIn(element.getEnclosedElements())) {
|
||||
if (this.metadataEnv.getReadOperationAnnotation(method) != null
|
||||
|
@ -97,15 +97,10 @@ class MetadataGenerationEnvironment {
|
||||
|
||||
private final String nameAnnotation;
|
||||
|
||||
private final String importAsConfigurationPropertiesBeanAnnotation;
|
||||
|
||||
private final String importAsConfigurationPropertiesBeansAnnotation;
|
||||
|
||||
MetadataGenerationEnvironment(ProcessingEnvironment environment, String configurationPropertiesAnnotation,
|
||||
String nestedConfigurationPropertyAnnotation, String deprecatedConfigurationPropertyAnnotation,
|
||||
String constructorBindingAnnotation, String defaultValueAnnotation, String endpointAnnotation,
|
||||
String readOperationAnnotation, String nameAnnotation, String importAsConfigurationPropertiesBeanAnnotation,
|
||||
String importAsConfigurationPropertiesBeansAnnotation) {
|
||||
String readOperationAnnotation, String nameAnnotation) {
|
||||
this.typeUtils = new TypeUtils(environment);
|
||||
this.elements = environment.getElementUtils();
|
||||
this.messager = environment.getMessager();
|
||||
@ -118,8 +113,6 @@ class MetadataGenerationEnvironment {
|
||||
this.endpointAnnotation = endpointAnnotation;
|
||||
this.readOperationAnnotation = readOperationAnnotation;
|
||||
this.nameAnnotation = nameAnnotation;
|
||||
this.importAsConfigurationPropertiesBeanAnnotation = importAsConfigurationPropertiesBeanAnnotation;
|
||||
this.importAsConfigurationPropertiesBeansAnnotation = importAsConfigurationPropertiesBeansAnnotation;
|
||||
}
|
||||
|
||||
private static FieldValuesParser resolveFieldValuesParser(ProcessingEnvironment env) {
|
||||
@ -265,14 +258,6 @@ class MetadataGenerationEnvironment {
|
||||
return this.elements.getTypeElement(this.configurationPropertiesAnnotation);
|
||||
}
|
||||
|
||||
TypeElement getImportAsConfigurationPropertiesBeansAnnotation() {
|
||||
return this.elements.getTypeElement(this.importAsConfigurationPropertiesBeanAnnotation);
|
||||
}
|
||||
|
||||
TypeElement getImportAsConfigurationPropertiesBeansAnnotationElement() {
|
||||
return this.elements.getTypeElement(this.importAsConfigurationPropertiesBeansAnnotation);
|
||||
}
|
||||
|
||||
AnnotationMirror getConfigurationPropertiesAnnotation(Element element) {
|
||||
return getAnnotation(element, this.configurationPropertiesAnnotation);
|
||||
}
|
||||
@ -297,22 +282,6 @@ class MetadataGenerationEnvironment {
|
||||
return getAnnotation(element, this.nameAnnotation);
|
||||
}
|
||||
|
||||
List<AnnotationMirror> getImportAsConfigurationPropertiesBeanAnnotations(Element element) {
|
||||
List<AnnotationMirror> annotations = new ArrayList<>();
|
||||
AnnotationMirror importBean = getAnnotation(element, this.importAsConfigurationPropertiesBeanAnnotation);
|
||||
if (importBean != null) {
|
||||
annotations.add(importBean);
|
||||
}
|
||||
AnnotationMirror importBeans = getAnnotation(element, this.importAsConfigurationPropertiesBeansAnnotation);
|
||||
if (importBeans != null) {
|
||||
AnnotationValue value = importBeans.getElementValues().values().iterator().next();
|
||||
for (Object contained : (List<?>) value.getValue()) {
|
||||
annotations.add((AnnotationMirror) contained);
|
||||
}
|
||||
}
|
||||
return Collections.unmodifiableList(annotations);
|
||||
}
|
||||
|
||||
boolean hasNullableAnnotation(Element element) {
|
||||
return getAnnotation(element, NULLABLE_ANNOTATION) != null;
|
||||
}
|
||||
|
@ -49,19 +49,16 @@ class PropertyDescriptorResolver {
|
||||
* specified {@link TypeElement type} based on the specified {@link ExecutableElement
|
||||
* factory method}, if any.
|
||||
* @param type the target type
|
||||
* @param fromImport it the type was imported via a
|
||||
* {@code @ImportAsConfigurationPropertiesBean}
|
||||
* @param factoryMethod the method that triggered the metadata for that {@code type}
|
||||
* or {@code null}
|
||||
* @return the candidate properties for metadata generation
|
||||
*/
|
||||
Stream<PropertyDescriptor<?>> resolve(TypeElement type, boolean fromImport, ExecutableElement factoryMethod) {
|
||||
Stream<PropertyDescriptor<?>> resolve(TypeElement type, ExecutableElement factoryMethod) {
|
||||
TypeElementMembers members = new TypeElementMembers(this.environment, type);
|
||||
if (factoryMethod != null) {
|
||||
return resolveJavaBeanProperties(type, factoryMethod, members);
|
||||
}
|
||||
return resolve(ConfigurationPropertiesTypeElement.of(type, fromImport, this.environment), factoryMethod,
|
||||
members);
|
||||
return resolve(ConfigurationPropertiesTypeElement.of(type, this.environment), factoryMethod, members);
|
||||
}
|
||||
|
||||
private Stream<PropertyDescriptor<?>> resolve(ConfigurationPropertiesTypeElement type,
|
||||
@ -181,29 +178,20 @@ class PropertyDescriptorResolver {
|
||||
return boundConstructor;
|
||||
}
|
||||
|
||||
static ConfigurationPropertiesTypeElement of(TypeElement type, boolean fromImport,
|
||||
MetadataGenerationEnvironment env) {
|
||||
static ConfigurationPropertiesTypeElement of(TypeElement type, MetadataGenerationEnvironment env) {
|
||||
boolean constructorBoundType = isConstructorBoundType(type, env);
|
||||
List<ExecutableElement> constructors = ElementFilter.constructorsIn(type.getEnclosedElements());
|
||||
List<ExecutableElement> boundConstructors = constructors.stream()
|
||||
.filter(env::hasConstructorBindingAnnotation).collect(Collectors.toList());
|
||||
boolean constructorBoundType = isConstructorBoundType(type, fromImport, constructors, env);
|
||||
return new ConfigurationPropertiesTypeElement(type, constructorBoundType, constructors, boundConstructors);
|
||||
}
|
||||
|
||||
private static boolean isConstructorBoundType(TypeElement type, boolean fromImport,
|
||||
List<ExecutableElement> constructors, MetadataGenerationEnvironment env) {
|
||||
private static boolean isConstructorBoundType(TypeElement type, MetadataGenerationEnvironment env) {
|
||||
if (env.hasConstructorBindingAnnotation(type)) {
|
||||
return true;
|
||||
}
|
||||
if (type.getNestingKind() == NestingKind.MEMBER) {
|
||||
return isConstructorBoundType((TypeElement) type.getEnclosingElement(), false, constructors, env);
|
||||
}
|
||||
if (fromImport) {
|
||||
for (ExecutableElement constructor : constructors) {
|
||||
if (!constructor.getParameters().isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return isConstructorBoundType((TypeElement) type.getEnclosingElement(), env);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -1,81 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2020 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.configurationprocessor;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata;
|
||||
import org.springframework.boot.configurationprocessor.metadata.Metadata;
|
||||
import org.springframework.boot.configurationsample.ImportAsConfigurationPropertiesBean;
|
||||
import org.springframework.boot.configurationsample.ImportAsConfigurationPropertiesBeans;
|
||||
import org.springframework.boot.configurationsample.importbean.ImportAnnotatedJavaBean;
|
||||
import org.springframework.boot.configurationsample.importbean.ImportJavaBeanConfigurationPropertiesBean;
|
||||
import org.springframework.boot.configurationsample.importbean.ImportMultipleTypeConfigurationPropertiesBean;
|
||||
import org.springframework.boot.configurationsample.importbean.ImportRepeatedConfigurationPropertiesBean;
|
||||
import org.springframework.boot.configurationsample.importbean.ImportValueObjectConfigurationPropertiesBean;
|
||||
import org.springframework.boot.configurationsample.importbean.ImportedAnnotatedJavaBean;
|
||||
import org.springframework.boot.configurationsample.importbean.ImportedJavaBean;
|
||||
import org.springframework.boot.configurationsample.importbean.ImportedValueObject;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link ImportAsConfigurationPropertiesBean} and
|
||||
* {@link ImportAsConfigurationPropertiesBeans}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class ImportBeanTests extends AbstractMetadataGenerationTests {
|
||||
|
||||
@Test
|
||||
void importValueObjectConfigurationPropertiesBean() {
|
||||
ConfigurationMetadata metadata = compile(ImportValueObjectConfigurationPropertiesBean.class);
|
||||
assertThat(metadata)
|
||||
.has(Metadata.withProperty("importbean.value", String.class).fromSource(ImportedValueObject.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void importJavaBeanConfigurationPropertiesBean() {
|
||||
ConfigurationMetadata metadata = compile(ImportJavaBeanConfigurationPropertiesBean.class);
|
||||
assertThat(metadata)
|
||||
.has(Metadata.withProperty("importbean.name", String.class).fromSource(ImportedJavaBean.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void importMultipleTypeConfigurationPropertiesBean() {
|
||||
ConfigurationMetadata metadata = compile(ImportMultipleTypeConfigurationPropertiesBean.class);
|
||||
assertThat(metadata)
|
||||
.has(Metadata.withProperty("importbean.value", String.class).fromSource(ImportedValueObject.class));
|
||||
assertThat(metadata)
|
||||
.has(Metadata.withProperty("importbean.name", String.class).fromSource(ImportedJavaBean.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void importRepeatedConfigurationPropertiesBean() {
|
||||
ConfigurationMetadata metadata = compile(ImportRepeatedConfigurationPropertiesBean.class);
|
||||
assertThat(metadata).has(Metadata.withProperty("vo.value", String.class).fromSource(ImportedValueObject.class));
|
||||
assertThat(metadata).has(Metadata.withProperty("jb.name", String.class).fromSource(ImportedJavaBean.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void importAnnotatedJavaBean() {
|
||||
ConfigurationMetadata metadata = compile(ImportAnnotatedJavaBean.class);
|
||||
assertThat(metadata)
|
||||
.has(Metadata.withProperty("test.name", String.class).fromSource(ImportedAnnotatedJavaBean.class));
|
||||
}
|
||||
|
||||
}
|
@ -39,9 +39,7 @@ class MetadataGenerationEnvironmentFactory implements Function<ProcessingEnviron
|
||||
TestConfigurationMetadataAnnotationProcessor.DEFAULT_VALUE_ANNOTATION,
|
||||
TestConfigurationMetadataAnnotationProcessor.ENDPOINT_ANNOTATION,
|
||||
TestConfigurationMetadataAnnotationProcessor.READ_OPERATION_ANNOTATION,
|
||||
TestConfigurationMetadataAnnotationProcessor.NAME_ANNOTATION,
|
||||
TestConfigurationMetadataAnnotationProcessor.IMPORT_AS_CONFIGURATION_PROPERTIES_BEAN_ANNOATION,
|
||||
TestConfigurationMetadataAnnotationProcessor.IMPORT_AS_CONFIGURATION_PROPERTIES_BEANS_ANNOATION);
|
||||
TestConfigurationMetadataAnnotationProcessor.NAME_ANNOTATION);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -74,9 +74,9 @@ class PropertyDescriptorResolverTests {
|
||||
Arrays.asList(HierarchicalPropertiesParent.class, HierarchicalPropertiesGrandparent.class),
|
||||
(type, metadataEnv) -> {
|
||||
PropertyDescriptorResolver resolver = new PropertyDescriptorResolver(metadataEnv);
|
||||
assertThat(resolver.resolve(type, false, null).map(PropertyDescriptor::getName))
|
||||
.containsExactly("third", "second", "first");
|
||||
assertThat(resolver.resolve(type, false, null)
|
||||
assertThat(resolver.resolve(type, null).map(PropertyDescriptor::getName)).containsExactly("third",
|
||||
"second", "first");
|
||||
assertThat(resolver.resolve(type, null)
|
||||
.map((descriptor) -> descriptor.resolveItemMetadata("test", metadataEnv))
|
||||
.map(ItemMetadata::getDefaultValue)).containsExactly("three", "two", "one");
|
||||
});
|
||||
@ -155,7 +155,7 @@ class PropertyDescriptorResolverTests {
|
||||
Consumer<Stream<PropertyDescriptor<?>>> stream) {
|
||||
return (element, metadataEnv) -> {
|
||||
PropertyDescriptorResolver resolver = new PropertyDescriptorResolver(metadataEnv);
|
||||
stream.accept(resolver.resolve(element, false, null));
|
||||
stream.accept(resolver.resolve(element, null));
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -57,10 +57,6 @@ public class TestConfigurationMetadataAnnotationProcessor extends ConfigurationM
|
||||
|
||||
public static final String NAME_ANNOTATION = "org.springframework.boot.configurationsample.Name";
|
||||
|
||||
public static final String IMPORT_AS_CONFIGURATION_PROPERTIES_BEAN_ANNOATION = "org.springframework.boot.configurationsample.ImportAsConfigurationPropertiesBean";
|
||||
|
||||
public static final String IMPORT_AS_CONFIGURATION_PROPERTIES_BEANS_ANNOATION = "org.springframework.boot.configurationsample.ImportAsConfigurationPropertiesBeans";
|
||||
|
||||
private ConfigurationMetadata metadata;
|
||||
|
||||
private final File outputLocation;
|
||||
@ -109,16 +105,6 @@ public class TestConfigurationMetadataAnnotationProcessor extends ConfigurationM
|
||||
return NAME_ANNOTATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String importAsConfigurationPropertiesBeanAnnotation() {
|
||||
return IMPORT_AS_CONFIGURATION_PROPERTIES_BEAN_ANNOATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String importAsConfigurationPropertiesBeansAnnotation() {
|
||||
return IMPORT_AS_CONFIGURATION_PROPERTIES_BEANS_ANNOATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ConfigurationMetadata writeMetaData() throws Exception {
|
||||
super.writeMetaData();
|
||||
|
@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2020 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.configurationsample;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
|
||||
/**
|
||||
* Alternative to Spring Boot's {@code ImportAsConfigurationPropertiesBean} for testing
|
||||
* (removes the need for a dependency on the real annotation).
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@ConfigurationProperties
|
||||
@Repeatable(ImportAsConfigurationPropertiesBeans.class)
|
||||
public @interface ImportAsConfigurationPropertiesBean {
|
||||
|
||||
Class<?>[] type();
|
||||
|
||||
@AliasFor(annotation = ConfigurationProperties.class)
|
||||
String prefix() default "";
|
||||
|
||||
@AliasFor(annotation = ConfigurationProperties.class)
|
||||
boolean ignoreInvalidFields() default false;
|
||||
|
||||
@AliasFor(annotation = ConfigurationProperties.class)
|
||||
boolean ignoreUnknownFields() default true;
|
||||
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2020 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.configurationsample;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Alternative to Spring Boot's {@code ImportAsConfigurationPropertiesBeans} for testing
|
||||
* (removes the need for a dependency on the real annotation).
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface ImportAsConfigurationPropertiesBeans {
|
||||
|
||||
ImportAsConfigurationPropertiesBean[] value();
|
||||
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2020 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.configurationsample.importbean;
|
||||
|
||||
import org.springframework.boot.configurationsample.ImportAsConfigurationPropertiesBean;
|
||||
|
||||
/**
|
||||
* An import of a java bean.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@ImportAsConfigurationPropertiesBean(type = ImportedAnnotatedJavaBean.class)
|
||||
public class ImportAnnotatedJavaBean {
|
||||
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2020 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.configurationsample.importbean;
|
||||
|
||||
import org.springframework.boot.configurationsample.ImportAsConfigurationPropertiesBean;
|
||||
|
||||
/**
|
||||
* An import of a java bean.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@ImportAsConfigurationPropertiesBean(type = ImportedJavaBean.class, prefix = "importbean")
|
||||
public class ImportJavaBeanConfigurationPropertiesBean {
|
||||
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2020 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.configurationsample.importbean;
|
||||
|
||||
import org.springframework.boot.configurationsample.ImportAsConfigurationPropertiesBean;
|
||||
|
||||
/**
|
||||
* An import of a java bean and a value object.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@ImportAsConfigurationPropertiesBean(type = { ImportedJavaBean.class, ImportedValueObject.class },
|
||||
prefix = "importbean")
|
||||
public class ImportMultipleTypeConfigurationPropertiesBean {
|
||||
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2020 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.configurationsample.importbean;
|
||||
|
||||
import org.springframework.boot.configurationsample.ImportAsConfigurationPropertiesBean;
|
||||
|
||||
/**
|
||||
* An import of a java bean and a value object.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@ImportAsConfigurationPropertiesBean(type = ImportedJavaBean.class, prefix = "jb")
|
||||
@ImportAsConfigurationPropertiesBean(type = ImportedValueObject.class, prefix = "vo")
|
||||
public class ImportRepeatedConfigurationPropertiesBean {
|
||||
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2020 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.configurationsample.importbean;
|
||||
|
||||
import org.springframework.boot.configurationsample.ImportAsConfigurationPropertiesBean;
|
||||
|
||||
/**
|
||||
* An import of a value object.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@ImportAsConfigurationPropertiesBean(type = ImportedValueObject.class, prefix = "importbean")
|
||||
public class ImportValueObjectConfigurationPropertiesBean {
|
||||
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2020 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.configurationsample.importbean;
|
||||
|
||||
import org.springframework.boot.configurationsample.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* Java bean that can be imported.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "test")
|
||||
public class ImportedAnnotatedJavaBean {
|
||||
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2020 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.configurationsample.importbean;
|
||||
|
||||
/**
|
||||
* Java bean that can be imported.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class ImportedJavaBean {
|
||||
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2020 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.configurationsample.importbean;
|
||||
|
||||
/**
|
||||
* Value object that can be imported.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class ImportedValueObject {
|
||||
|
||||
private final String value;
|
||||
|
||||
public ImportedValueObject(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
}
|
@ -18,7 +18,6 @@ package org.springframework.boot.context.properties;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
@ -76,7 +75,7 @@ public final class ConfigurationPropertiesBean {
|
||||
this.instance = instance;
|
||||
this.annotation = annotation;
|
||||
this.bindTarget = bindTarget;
|
||||
this.bindMethod = BindMethod.forBindable(bindTarget);
|
||||
this.bindMethod = BindMethod.forType(bindTarget.getType().resolve());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -176,8 +175,7 @@ public final class ConfigurationPropertiesBean {
|
||||
if (beanFactory.findAnnotationOnBean(beanName, ConfigurationProperties.class) != null) {
|
||||
return true;
|
||||
}
|
||||
BeanDefinition beanDefinition = findBeanDefinition(beanFactory, beanName);
|
||||
Method factoryMethod = findFactoryMethod(beanFactory, beanDefinition);
|
||||
Method factoryMethod = findFactoryMethod(beanFactory, beanName);
|
||||
return findMergedAnnotation(factoryMethod, ConfigurationProperties.class).isPresent();
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
@ -199,41 +197,33 @@ public final class ConfigurationPropertiesBean {
|
||||
* {@link ConfigurationProperties @ConfigurationProperties}
|
||||
*/
|
||||
public static ConfigurationPropertiesBean get(ApplicationContext applicationContext, Object bean, String beanName) {
|
||||
ConfigurableListableBeanFactory beanFactory = getBeanFactory(applicationContext);
|
||||
BeanDefinition beanDefinition = findBeanDefinition(beanFactory, beanName);
|
||||
Method factoryMethod = findFactoryMethod(beanFactory, beanDefinition);
|
||||
ConfigurationProperties annotation = findAnnotation(beanDefinition);
|
||||
boolean deduceBindConstructor = (beanDefinition instanceof ConfigurationPropertiesValueObjectBeanDefinition)
|
||||
? ((ConfigurationPropertiesValueObjectBeanDefinition) beanDefinition).isDeduceBindConstructor() : false;
|
||||
return create(beanName, bean, bean.getClass(), factoryMethod, annotation, deduceBindConstructor);
|
||||
Method factoryMethod = findFactoryMethod(applicationContext, beanName);
|
||||
return create(beanName, bean, bean.getClass(), factoryMethod);
|
||||
}
|
||||
|
||||
private static ConfigurableListableBeanFactory getBeanFactory(ApplicationContext applicationContext) {
|
||||
private static Method findFactoryMethod(ApplicationContext applicationContext, String beanName) {
|
||||
if (applicationContext instanceof ConfigurableApplicationContext) {
|
||||
return ((ConfigurableApplicationContext) applicationContext).getBeanFactory();
|
||||
return findFactoryMethod((ConfigurableApplicationContext) applicationContext, beanName);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static BeanDefinition findBeanDefinition(ConfigurableListableBeanFactory beanFactory, String beanName) {
|
||||
if (beanFactory != null && beanFactory.containsBeanDefinition(beanName)) {
|
||||
return beanFactory.getMergedBeanDefinition(beanName);
|
||||
}
|
||||
return null;
|
||||
private static Method findFactoryMethod(ConfigurableApplicationContext applicationContext, String beanName) {
|
||||
return findFactoryMethod(applicationContext.getBeanFactory(), beanName);
|
||||
}
|
||||
|
||||
private static Method findFactoryMethod(ConfigurableListableBeanFactory beanFactory,
|
||||
BeanDefinition beanDefinition) {
|
||||
if (beanFactory == null || beanDefinition == null) {
|
||||
return null;
|
||||
}
|
||||
if (beanDefinition instanceof RootBeanDefinition) {
|
||||
Method resolvedFactoryMethod = ((RootBeanDefinition) beanDefinition).getResolvedFactoryMethod();
|
||||
if (resolvedFactoryMethod != null) {
|
||||
return resolvedFactoryMethod;
|
||||
private static Method findFactoryMethod(ConfigurableListableBeanFactory beanFactory, String beanName) {
|
||||
if (beanFactory.containsBeanDefinition(beanName)) {
|
||||
BeanDefinition beanDefinition = beanFactory.getMergedBeanDefinition(beanName);
|
||||
if (beanDefinition instanceof RootBeanDefinition) {
|
||||
Method resolvedFactoryMethod = ((RootBeanDefinition) beanDefinition).getResolvedFactoryMethod();
|
||||
if (resolvedFactoryMethod != null) {
|
||||
return resolvedFactoryMethod;
|
||||
}
|
||||
}
|
||||
return findFactoryMethodUsingReflection(beanFactory, beanDefinition);
|
||||
}
|
||||
return findFactoryMethodUsingReflection(beanFactory, beanDefinition);
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Method findFactoryMethodUsingReflection(ConfigurableListableBeanFactory beanFactory,
|
||||
@ -256,19 +246,15 @@ public final class ConfigurationPropertiesBean {
|
||||
return factoryMethod.get();
|
||||
}
|
||||
|
||||
static ConfigurationPropertiesBean forValueObject(Class<?> beanClass, String beanName,
|
||||
MergedAnnotation<ConfigurationProperties> annotation, boolean deduceBindConstructor) {
|
||||
ConfigurationPropertiesBean propertiesBean = create(beanName, null, beanClass, null,
|
||||
annotation.isPresent() ? annotation.synthesize() : null, deduceBindConstructor);
|
||||
static ConfigurationPropertiesBean forValueObject(Class<?> beanClass, String beanName) {
|
||||
ConfigurationPropertiesBean propertiesBean = create(beanName, null, beanClass, null);
|
||||
Assert.state(propertiesBean != null && propertiesBean.getBindMethod() == BindMethod.VALUE_OBJECT,
|
||||
() -> "Bean '" + beanName + "' is not a @ConfigurationProperties value object");
|
||||
return propertiesBean;
|
||||
}
|
||||
|
||||
private static ConfigurationPropertiesBean create(String name, Object instance, Class<?> type, Method factory,
|
||||
ConfigurationProperties annotation, boolean deduceBindConstructor) {
|
||||
annotation = (annotation != null) ? annotation
|
||||
: findAnnotation(instance, type, factory, ConfigurationProperties.class);
|
||||
private static ConfigurationPropertiesBean create(String name, Object instance, Class<?> type, Method factory) {
|
||||
ConfigurationProperties annotation = findAnnotation(instance, type, factory, ConfigurationProperties.class);
|
||||
if (annotation == null) {
|
||||
return null;
|
||||
}
|
||||
@ -281,19 +267,9 @@ public final class ConfigurationPropertiesBean {
|
||||
if (instance != null) {
|
||||
bindTarget = bindTarget.withExistingValue(instance);
|
||||
}
|
||||
if (deduceBindConstructor) {
|
||||
bindTarget = bindTarget.withAttribute(
|
||||
ConfigurationPropertiesBindConstructorProvider.DEDUCE_BIND_CONSTRUCTOR_ATTRIUBTE, true);
|
||||
}
|
||||
return new ConfigurationPropertiesBean(name, instance, annotation, bindTarget);
|
||||
}
|
||||
|
||||
private static ConfigurationProperties findAnnotation(BeanDefinition beanDefinition) {
|
||||
MergedAnnotation<ConfigurationProperties> annotation = ConfigurationPropertiesBeanDefinition
|
||||
.getAnnotation(beanDefinition);
|
||||
return (annotation.isPresent()) ? annotation.synthesize() : null;
|
||||
}
|
||||
|
||||
private static <A extends Annotation> A findAnnotation(Object instance, Class<?> type, Method factory,
|
||||
Class<A> annotationType) {
|
||||
MergedAnnotation<A> annotation = MergedAnnotation.missing();
|
||||
@ -332,27 +308,8 @@ public final class ConfigurationPropertiesBean {
|
||||
VALUE_OBJECT;
|
||||
|
||||
static BindMethod forType(Class<?> type) {
|
||||
return forType(type, false);
|
||||
}
|
||||
|
||||
static BindMethod forType(Class<?> type, boolean deduceBindConstructor) {
|
||||
Constructor<?> constructor = ConfigurationPropertiesBindConstructorProvider.INSTANCE
|
||||
.getBindConstructor(type, deduceBindConstructor, false);
|
||||
if (deduceBindConstructor) {
|
||||
Assert.state(constructor != null,
|
||||
() -> "Unable to deduce @ConfigurationProperties bind method for " + type.getName());
|
||||
}
|
||||
return hasParameters(constructor) ? VALUE_OBJECT : JAVA_BEAN;
|
||||
}
|
||||
|
||||
static BindMethod forBindable(Bindable<?> bindable) {
|
||||
Constructor<?> constructor = ConfigurationPropertiesBindConstructorProvider.INSTANCE
|
||||
.getBindConstructor(bindable, false);
|
||||
return hasParameters(constructor) ? VALUE_OBJECT : JAVA_BEAN;
|
||||
}
|
||||
|
||||
private static boolean hasParameters(Constructor<?> constructor) {
|
||||
return constructor != null && constructor.getParameterCount() > 0;
|
||||
return (ConfigurationPropertiesBindConstructorProvider.INSTANCE.getBindConstructor(type, false) != null)
|
||||
? VALUE_OBJECT : JAVA_BEAN;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2020 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.context.properties;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.GenericBeanDefinition;
|
||||
import org.springframework.core.Conventions;
|
||||
import org.springframework.core.annotation.MergedAnnotation;
|
||||
|
||||
/**
|
||||
* {@link BeanDefinition} that is used for registering
|
||||
* {@link ConfigurationProperties @ConfigurationProperties} beans.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class ConfigurationPropertiesBeanDefinition extends GenericBeanDefinition {
|
||||
|
||||
private static final String ANNOTATION_ATTRIBUTE = Conventions
|
||||
.getQualifiedAttributeName(ConfigurationPropertiesBeanDefinition.class, "annotation");
|
||||
|
||||
ConfigurationPropertiesBeanDefinition(Class<?> beanClass, MergedAnnotation<ConfigurationProperties> annotation) {
|
||||
setBeanClass(beanClass);
|
||||
setAttribute(ANNOTATION_ATTRIBUTE, annotation);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static MergedAnnotation<ConfigurationProperties> getAnnotation(BeanDefinition beanDefinition) {
|
||||
MergedAnnotation<ConfigurationProperties> annotation = (beanDefinition != null)
|
||||
? (MergedAnnotation<ConfigurationProperties>) beanDefinition.getAttribute(ANNOTATION_ATTRIBUTE) : null;
|
||||
return (annotation != null) ? annotation : MergedAnnotation.missing();
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* 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.
|
||||
@ -20,6 +20,7 @@ import org.springframework.beans.factory.HierarchicalBeanFactory;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.GenericBeanDefinition;
|
||||
import org.springframework.boot.context.properties.ConfigurationPropertiesBean.BindMethod;
|
||||
import org.springframework.core.annotation.MergedAnnotation;
|
||||
import org.springframework.core.annotation.MergedAnnotations;
|
||||
@ -46,14 +47,16 @@ final class ConfigurationPropertiesBeanRegistrar {
|
||||
this.beanFactory = (BeanFactory) this.registry;
|
||||
}
|
||||
|
||||
void register(Class<?> type, MergedAnnotation<ConfigurationProperties> annotation, boolean deduceBindConstructor) {
|
||||
MergedAnnotation<ConfigurationProperties> typeAnnotation = MergedAnnotations
|
||||
void register(Class<?> type) {
|
||||
MergedAnnotation<ConfigurationProperties> annotation = MergedAnnotations
|
||||
.from(type, SearchStrategy.TYPE_HIERARCHY).get(ConfigurationProperties.class);
|
||||
annotation = (!typeAnnotation.isPresent()) ? annotation : typeAnnotation;
|
||||
annotation = (annotation != null) ? annotation : MergedAnnotation.missing();
|
||||
register(type, annotation);
|
||||
}
|
||||
|
||||
void register(Class<?> type, MergedAnnotation<ConfigurationProperties> annotation) {
|
||||
String name = getName(type, annotation);
|
||||
if (!containsBeanDefinition(name)) {
|
||||
registerBeanDefinition(name, type, annotation, deduceBindConstructor);
|
||||
registerBeanDefinition(name, type, annotation);
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,20 +81,19 @@ final class ConfigurationPropertiesBeanRegistrar {
|
||||
}
|
||||
|
||||
private void registerBeanDefinition(String beanName, Class<?> type,
|
||||
MergedAnnotation<ConfigurationProperties> annotation, boolean deduceBindConstructor) {
|
||||
MergedAnnotation<ConfigurationProperties> annotation) {
|
||||
Assert.state(annotation.isPresent(), () -> "No " + ConfigurationProperties.class.getSimpleName()
|
||||
+ " annotation found on '" + type.getName() + "'.");
|
||||
this.registry.registerBeanDefinition(beanName,
|
||||
createBeanDefinition(beanName, type, annotation, deduceBindConstructor));
|
||||
this.registry.registerBeanDefinition(beanName, createBeanDefinition(beanName, type));
|
||||
}
|
||||
|
||||
private BeanDefinition createBeanDefinition(String beanName, Class<?> type,
|
||||
MergedAnnotation<ConfigurationProperties> annotation, boolean deduceBindConstructor) {
|
||||
if (BindMethod.forType(type, deduceBindConstructor) == BindMethod.VALUE_OBJECT) {
|
||||
return new ConfigurationPropertiesValueObjectBeanDefinition(this.beanFactory, beanName, type, annotation,
|
||||
deduceBindConstructor);
|
||||
private BeanDefinition createBeanDefinition(String beanName, Class<?> type) {
|
||||
if (BindMethod.forType(type) == BindMethod.VALUE_OBJECT) {
|
||||
return new ConfigurationPropertiesValueObjectBeanDefinition(this.beanFactory, beanName, type);
|
||||
}
|
||||
return new ConfigurationPropertiesBeanDefinition(type, annotation);
|
||||
GenericBeanDefinition definition = new GenericBeanDefinition();
|
||||
definition.setBeanClass(type);
|
||||
return definition;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -21,7 +21,6 @@ import java.lang.reflect.Constructor;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.boot.context.properties.bind.BindConstructorProvider;
|
||||
import org.springframework.boot.context.properties.bind.Bindable;
|
||||
import org.springframework.core.Conventions;
|
||||
import org.springframework.core.KotlinDetector;
|
||||
import org.springframework.core.annotation.MergedAnnotations;
|
||||
import org.springframework.util.Assert;
|
||||
@ -37,35 +36,19 @@ class ConfigurationPropertiesBindConstructorProvider implements BindConstructorP
|
||||
|
||||
static final ConfigurationPropertiesBindConstructorProvider INSTANCE = new ConfigurationPropertiesBindConstructorProvider();
|
||||
|
||||
static final String DEDUCE_BIND_CONSTRUCTOR_ATTRIUBTE = Conventions
|
||||
.getQualifiedAttributeName(ConfigurationPropertiesBindConstructorProvider.class, "deduceBindConstructor");
|
||||
|
||||
@Override
|
||||
public Constructor<?> getBindConstructor(Bindable<?> bindable, boolean isNestedConstructorBinding) {
|
||||
Boolean deduceBindConstructor = (Boolean) bindable.getAttribute(DEDUCE_BIND_CONSTRUCTOR_ATTRIUBTE);
|
||||
return getBindConstructor(bindable.getType().resolve(), Boolean.TRUE.equals(deduceBindConstructor),
|
||||
isNestedConstructorBinding);
|
||||
return getBindConstructor(bindable.getType().resolve(), isNestedConstructorBinding);
|
||||
}
|
||||
|
||||
Constructor<?> getBindConstructor(Class<?> type, boolean deduceBindConstructor,
|
||||
boolean isNestedConstructorBinding) {
|
||||
Constructor<?> getBindConstructor(Class<?> type, boolean isNestedConstructorBinding) {
|
||||
if (type == null) {
|
||||
return null;
|
||||
}
|
||||
Constructor<?> constructor = findConstructorBindingAnnotatedConstructor(type);
|
||||
if (constructor != null) {
|
||||
return constructor;
|
||||
}
|
||||
boolean isConstructorBindingAnnotatedType = isConstructorBindingAnnotatedType(type);
|
||||
if (deduceBindConstructor || isNestedConstructorBinding || isConstructorBindingAnnotatedType) {
|
||||
if (constructor == null && (isConstructorBindingAnnotatedType(type) || isNestedConstructorBinding)) {
|
||||
constructor = deduceBindConstructor(type);
|
||||
}
|
||||
if (deduceBindConstructor && isConstructorBindingAnnotatedType && !isNestedConstructorBinding) {
|
||||
Assert.state(constructor != null,
|
||||
() -> "Unable to deduce constructor for @ConstructorBinding class " + type.getName());
|
||||
Assert.state(constructor.getParameterCount() > 0,
|
||||
() -> "Deduced no-args constructor for @ConstructorBinding class " + type.getName());
|
||||
}
|
||||
return constructor;
|
||||
}
|
||||
|
||||
@ -103,7 +86,7 @@ class ConfigurationPropertiesBindConstructorProvider implements BindConstructorP
|
||||
return deducedKotlinBindConstructor(type);
|
||||
}
|
||||
Constructor<?>[] constructors = type.getDeclaredConstructors();
|
||||
if (constructors.length == 1) {
|
||||
if (constructors.length == 1 && constructors[0].getParameterCount() > 0) {
|
||||
return constructors[0];
|
||||
}
|
||||
return null;
|
||||
@ -111,7 +94,7 @@ class ConfigurationPropertiesBindConstructorProvider implements BindConstructorP
|
||||
|
||||
private Constructor<?> deducedKotlinBindConstructor(Class<?> type) {
|
||||
Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(type);
|
||||
if (primaryConstructor != null) {
|
||||
if (primaryConstructor != null && primaryConstructor.getParameterCount() > 0) {
|
||||
return primaryConstructor;
|
||||
}
|
||||
return null;
|
||||
|
@ -25,7 +25,6 @@ import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.PropertyEditorRegistry;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
@ -207,14 +206,7 @@ class ConfigurationPropertiesBinder {
|
||||
}
|
||||
|
||||
static ConfigurationPropertiesBinder get(BeanFactory beanFactory) {
|
||||
try {
|
||||
return beanFactory.getBean(BEAN_NAME, ConfigurationPropertiesBinder.class);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
throw new NoSuchBeanDefinitionException(ex.getBeanName(),
|
||||
"Unable to find ConfigurationPropertiesBinder bean '" + BEAN_NAME
|
||||
+ "', ensure @EnableConfigurationProperties has been specified");
|
||||
}
|
||||
return beanFactory.getBean(BEAN_NAME, ConfigurationPropertiesBinder.class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -108,7 +108,7 @@ class ConfigurationPropertiesScanRegistrar implements ImportBeanDefinitionRegist
|
||||
|
||||
private void register(ConfigurationPropertiesBeanRegistrar registrar, Class<?> type) {
|
||||
if (!isComponent(type)) {
|
||||
registrar.register(type, null, false);
|
||||
registrar.register(type);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* 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.
|
||||
@ -18,7 +18,7 @@ package org.springframework.boot.context.properties;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.core.annotation.MergedAnnotation;
|
||||
import org.springframework.beans.factory.support.GenericBeanDefinition;
|
||||
|
||||
/**
|
||||
* {@link BeanDefinition} that is used for registering
|
||||
@ -29,30 +29,21 @@ import org.springframework.core.annotation.MergedAnnotation;
|
||||
* @author Madhura Bhave
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
final class ConfigurationPropertiesValueObjectBeanDefinition extends ConfigurationPropertiesBeanDefinition {
|
||||
final class ConfigurationPropertiesValueObjectBeanDefinition extends GenericBeanDefinition {
|
||||
|
||||
private final BeanFactory beanFactory;
|
||||
|
||||
private final String beanName;
|
||||
|
||||
private final boolean deduceBindConstructor;
|
||||
|
||||
ConfigurationPropertiesValueObjectBeanDefinition(BeanFactory beanFactory, String beanName, Class<?> beanClass,
|
||||
MergedAnnotation<ConfigurationProperties> annotation, boolean deduceBindConstructor) {
|
||||
super(beanClass, annotation);
|
||||
ConfigurationPropertiesValueObjectBeanDefinition(BeanFactory beanFactory, String beanName, Class<?> beanClass) {
|
||||
this.beanFactory = beanFactory;
|
||||
this.beanName = beanName;
|
||||
this.deduceBindConstructor = deduceBindConstructor;
|
||||
setBeanClass(beanClass);
|
||||
setInstanceSupplier(this::createBean);
|
||||
}
|
||||
|
||||
boolean isDeduceBindConstructor() {
|
||||
return this.deduceBindConstructor;
|
||||
}
|
||||
|
||||
private Object createBean() {
|
||||
ConfigurationPropertiesBean bean = ConfigurationPropertiesBean.forValueObject(getBeanClass(), this.beanName,
|
||||
getAnnotation(this), this.deduceBindConstructor);
|
||||
ConfigurationPropertiesBean bean = ConfigurationPropertiesBean.forValueObject(getBeanClass(), this.beanName);
|
||||
ConfigurationPropertiesBinder binder = ConfigurationPropertiesBinder.get(this.beanFactory);
|
||||
try {
|
||||
return binder.bindOrCreate(bean);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* 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.
|
||||
@ -51,7 +51,6 @@ public @interface EnableConfigurationProperties {
|
||||
* {@link ConfigurationProperties @ConfigurationProperties} annotated beans with
|
||||
* Spring. Standard Spring Beans will also be scanned regardless of this value.
|
||||
* @return {@code @ConfigurationProperties} annotated beans to register
|
||||
* @see ImportAsConfigurationPropertiesBean
|
||||
*/
|
||||
Class<?>[] value() default {};
|
||||
|
||||
|
@ -37,9 +37,7 @@ class EnableConfigurationPropertiesRegistrar implements ImportBeanDefinitionRegi
|
||||
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
|
||||
registerInfrastructureBeans(registry);
|
||||
ConfigurationPropertiesBeanRegistrar beanRegistrar = new ConfigurationPropertiesBeanRegistrar(registry);
|
||||
for (Class<?> type : getTypes(metadata)) {
|
||||
beanRegistrar.register(type, null, false);
|
||||
}
|
||||
getTypes(metadata).forEach(beanRegistrar::register);
|
||||
}
|
||||
|
||||
private Set<Class<?>> getTypes(AnnotationMetadata metadata) {
|
||||
|
@ -1,100 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2020 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.context.properties;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
|
||||
/**
|
||||
* Imports classes as {@link ConfigurationProperties @ConfigurationProperties} beans. Can
|
||||
* be used to import {@link ConfigurationProperties @ConfigurationProperties} annotated
|
||||
* types or third-party classes as configuration property beans.
|
||||
* <p>
|
||||
* Classes imported via this annotation that have a default constructor will use
|
||||
* {@code setter} binding, those with a non-default constructor will use
|
||||
* {@link ConstructorBinding @ConstructorBinding}. If you are looking to inject beans into
|
||||
* a constructor, you should use a regular {@link Configuration @Configuration} class
|
||||
* {@code @Bean} method instead.
|
||||
* <p>
|
||||
* The {@code @ConfigurationProperties} alias attributes defined on this class will only
|
||||
* be used if the imported class is not itself annotated
|
||||
* with{@code @ConfigurationProperties}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 2.4.0
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@EnableConfigurationProperties
|
||||
@ConfigurationProperties
|
||||
@Repeatable(ImportAsConfigurationPropertiesBeans.class)
|
||||
@Import(ImportAsConfigurationPropertiesBeanRegistrar.class)
|
||||
public @interface ImportAsConfigurationPropertiesBean {
|
||||
|
||||
/**
|
||||
* One or more types that should be imported as a bean.
|
||||
* @return the types to import
|
||||
*/
|
||||
@AliasFor("type")
|
||||
Class<?>[] value() default {};
|
||||
|
||||
/**
|
||||
* One or more types that should be imported as a bean.
|
||||
* @return the types to import
|
||||
*/
|
||||
@AliasFor("value")
|
||||
Class<?>[] type() default {};
|
||||
|
||||
/**
|
||||
* The prefix of the properties that are valid to bind to this object. A valid prefix
|
||||
* is defined by one or more words separated with dots (e.g.
|
||||
* {@code "acme.system.feature"}).
|
||||
* @return the prefix of the properties to bind
|
||||
* @see ConfigurationProperties#prefix()
|
||||
*/
|
||||
@AliasFor(annotation = ConfigurationProperties.class)
|
||||
String prefix() default "";
|
||||
|
||||
/**
|
||||
* Flag to indicate that when binding to this object invalid fields should be ignored.
|
||||
* Invalid means invalid according to the binder that is used, and usually this means
|
||||
* fields of the wrong type (or that cannot be coerced into the correct type).
|
||||
* @return the flag value (default false)
|
||||
* @see ConfigurationProperties#ignoreInvalidFields()
|
||||
*/
|
||||
@AliasFor(annotation = ConfigurationProperties.class)
|
||||
boolean ignoreInvalidFields() default false;
|
||||
|
||||
/**
|
||||
* Flag to indicate that when binding to this object unknown fields should be ignored.
|
||||
* An unknown field could be a sign of a mistake in the Properties.
|
||||
* @return the flag value (default true)
|
||||
* @see ConfigurationProperties#ignoreUnknownFields()
|
||||
*/
|
||||
@AliasFor(annotation = ConfigurationProperties.class)
|
||||
boolean ignoreUnknownFields() default true;
|
||||
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2020 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.context.properties;
|
||||
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.BeanNameGenerator;
|
||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
||||
import org.springframework.core.annotation.MergedAnnotation;
|
||||
import org.springframework.core.annotation.MergedAnnotations;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* {@link ImportBeanDefinitionRegistrar} for
|
||||
* {@link ImportAsConfigurationPropertiesBean @ImportAsConfigurationPropertiesBean}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class ImportAsConfigurationPropertiesBeanRegistrar implements ImportBeanDefinitionRegistrar {
|
||||
|
||||
@Override
|
||||
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,
|
||||
BeanNameGenerator importBeanNameGenerator) {
|
||||
try {
|
||||
ConfigurationPropertiesBeanRegistrar registrar = new ConfigurationPropertiesBeanRegistrar(registry);
|
||||
MergedAnnotations annotations = importingClassMetadata.getAnnotations();
|
||||
registerBeans(registrar, annotations.get(ImportAsConfigurationPropertiesBeans.class));
|
||||
registerBean(registrar, annotations.get(ImportAsConfigurationPropertiesBean.class));
|
||||
}
|
||||
catch (RuntimeException ex) {
|
||||
throw new IllegalStateException("Unable process @ImportAsConfigurationPropertiesBean annotations from "
|
||||
+ importingClassMetadata.getClassName(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void registerBeans(ConfigurationPropertiesBeanRegistrar registrar,
|
||||
MergedAnnotation<ImportAsConfigurationPropertiesBeans> annotation) {
|
||||
if (!annotation.isPresent()) {
|
||||
return;
|
||||
}
|
||||
for (MergedAnnotation<ImportAsConfigurationPropertiesBean> containedAnnotation : annotation
|
||||
.getAnnotationArray(MergedAnnotation.VALUE, ImportAsConfigurationPropertiesBean.class)) {
|
||||
registerBean(registrar, containedAnnotation);
|
||||
}
|
||||
}
|
||||
|
||||
private void registerBean(ConfigurationPropertiesBeanRegistrar registrar,
|
||||
MergedAnnotation<ImportAsConfigurationPropertiesBean> annotation) {
|
||||
if (!annotation.isPresent()) {
|
||||
return;
|
||||
}
|
||||
Class<?>[] types = annotation.getClassArray("type");
|
||||
Assert.state(!ObjectUtils.isEmpty(types), "@ImportAsConfigurationPropertiesBean must declare types to import");
|
||||
MergedAnnotation<ConfigurationProperties> configurationPropertiesAnnotation = MergedAnnotations
|
||||
.from(annotation.synthesize()).get(ConfigurationProperties.class);
|
||||
for (Class<?> type : types) {
|
||||
registrar.register(type, configurationPropertiesAnnotation, true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2020 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.context.properties;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
* Container annotation that aggregates several
|
||||
* {@link ImportAsConfigurationPropertiesBean @ImportAsConfigurationPropertiesBean}
|
||||
* annotations.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 2.4.0
|
||||
* @see ImportAsConfigurationPropertiesBean
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@EnableConfigurationProperties
|
||||
@Import(ImportAsConfigurationPropertiesBeanRegistrar.class)
|
||||
public @interface ImportAsConfigurationPropertiesBeans {
|
||||
|
||||
/**
|
||||
* The contained
|
||||
* {@link ImportAsConfigurationPropertiesBean @ImportAsConfigurationPropertiesBean}
|
||||
* annotations.
|
||||
* @return the contained annotations
|
||||
*/
|
||||
ImportAsConfigurationPropertiesBean[] value();
|
||||
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* 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.
|
||||
@ -18,8 +18,6 @@ package org.springframework.boot.context.properties.bind;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@ -44,8 +42,6 @@ public final class Bindable<T> {
|
||||
|
||||
private static final Annotation[] NO_ANNOTATIONS = {};
|
||||
|
||||
private static final Map<String, Object> NO_ATTRIBUTES = Collections.emptyMap();
|
||||
|
||||
private final ResolvableType type;
|
||||
|
||||
private final ResolvableType boxedType;
|
||||
@ -54,15 +50,11 @@ public final class Bindable<T> {
|
||||
|
||||
private final Annotation[] annotations;
|
||||
|
||||
private final Map<String, Object> attributes;
|
||||
|
||||
private Bindable(ResolvableType type, ResolvableType boxedType, Supplier<T> value, Annotation[] annotations,
|
||||
Map<String, Object> attributes) {
|
||||
private Bindable(ResolvableType type, ResolvableType boxedType, Supplier<T> value, Annotation[] annotations) {
|
||||
this.type = type;
|
||||
this.boxedType = boxedType;
|
||||
this.value = value;
|
||||
this.annotations = annotations;
|
||||
this.attributes = attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -113,16 +105,6 @@ public final class Bindable<T> {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value of an attribute that has been associated with this
|
||||
* {@link Bindable}.
|
||||
* @param name the attribute name
|
||||
* @return the associated attribute value or {@code null}
|
||||
*/
|
||||
public Object getAttribute(String name) {
|
||||
return this.attributes.get(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
@ -135,7 +117,6 @@ public final class Bindable<T> {
|
||||
boolean result = true;
|
||||
result = result && nullSafeEquals(this.type.resolve(), other.type.resolve());
|
||||
result = result && nullSafeEquals(this.annotations, other.annotations);
|
||||
result = result && nullSafeEquals(this.attributes, other.attributes);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -145,7 +126,6 @@ public final class Bindable<T> {
|
||||
int result = 1;
|
||||
result = prime * result + ObjectUtils.nullSafeHashCode(this.type);
|
||||
result = prime * result + ObjectUtils.nullSafeHashCode(this.annotations);
|
||||
result = prime * result + ObjectUtils.nullSafeHashCode(this.attributes);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -155,7 +135,6 @@ public final class Bindable<T> {
|
||||
creator.append("type", this.type);
|
||||
creator.append("value", (this.value != null) ? "provided" : "none");
|
||||
creator.append("annotations", this.annotations);
|
||||
creator.append("attributes", this.attributes);
|
||||
return creator.toString();
|
||||
}
|
||||
|
||||
@ -170,19 +149,7 @@ public final class Bindable<T> {
|
||||
*/
|
||||
public Bindable<T> withAnnotations(Annotation... annotations) {
|
||||
return new Bindable<>(this.type, this.boxedType, this.value,
|
||||
(annotations != null) ? annotations : NO_ANNOTATIONS, this.attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an updated {@link Bindable} instance with the specified attribute.
|
||||
* @param name the attribute name
|
||||
* @param value the attribute value
|
||||
* @return an updated {@link Bindable}
|
||||
*/
|
||||
public Bindable<T> withAttribute(String name, Object value) {
|
||||
Map<String, Object> attributes = new HashMap<>(this.attributes);
|
||||
attributes.put(name, value);
|
||||
return new Bindable<>(this.type, this.boxedType, this.value, this.annotations, attributes);
|
||||
(annotations != null) ? annotations : NO_ANNOTATIONS);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -195,7 +162,7 @@ public final class Bindable<T> {
|
||||
existingValue == null || this.type.isArray() || this.boxedType.resolve().isInstance(existingValue),
|
||||
() -> "ExistingValue must be an instance of " + this.type);
|
||||
Supplier<T> value = (existingValue != null) ? () -> existingValue : null;
|
||||
return new Bindable<>(this.type, this.boxedType, value, this.annotations, this.attributes);
|
||||
return new Bindable<>(this.type, this.boxedType, value, this.annotations);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -204,7 +171,7 @@ public final class Bindable<T> {
|
||||
* @return an updated {@link Bindable}
|
||||
*/
|
||||
public Bindable<T> withSuppliedValue(Supplier<T> suppliedValue) {
|
||||
return new Bindable<>(this.type, this.boxedType, suppliedValue, this.annotations, this.attributes);
|
||||
return new Bindable<>(this.type, this.boxedType, suppliedValue, this.annotations);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -277,7 +244,7 @@ public final class Bindable<T> {
|
||||
public static <T> Bindable<T> of(ResolvableType type) {
|
||||
Assert.notNull(type, "Type must not be null");
|
||||
ResolvableType boxedType = box(type);
|
||||
return new Bindable<>(type, boxedType, null, NO_ANNOTATIONS, NO_ATTRIBUTES);
|
||||
return new Bindable<>(type, boxedType, null, NO_ANNOTATIONS);
|
||||
}
|
||||
|
||||
private static ResolvableType box(ResolvableType type) {
|
||||
|
@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2020 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.context.properties;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.GenericBeanDefinition;
|
||||
import org.springframework.core.annotation.MergedAnnotation;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link ConfigurationPropertiesBeanDefinition}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class ConfigurationPropertiesBeanDefinitionTests {
|
||||
|
||||
@Test
|
||||
void getAnnotationGetsAnnotation() {
|
||||
MergedAnnotation<ConfigurationProperties> annotation = MergedAnnotation.of(ConfigurationProperties.class);
|
||||
BeanDefinition definition = new ConfigurationPropertiesBeanDefinition(Example.class, annotation);
|
||||
assertThat(ConfigurationPropertiesBeanDefinition.getAnnotation(definition)).isSameAs(annotation);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getAnnotationWhenNullReturnsMissing() {
|
||||
assertThat(ConfigurationPropertiesBeanDefinition.getAnnotation(null)).isEqualTo(MergedAnnotation.missing());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getAnnotationWhenNoAttributeReturnsMissing() {
|
||||
GenericBeanDefinition definition = new GenericBeanDefinition();
|
||||
assertThat(ConfigurationPropertiesBeanDefinition.getAnnotation(definition))
|
||||
.isEqualTo(MergedAnnotation.missing());
|
||||
}
|
||||
|
||||
static class Example {
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* 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.
|
||||
@ -22,7 +22,6 @@ import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.GenericBeanDefinition;
|
||||
import org.springframework.core.annotation.MergedAnnotation;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
@ -43,7 +42,7 @@ class ConfigurationPropertiesBeanRegistrarTests {
|
||||
@Test
|
||||
void registerWhenNotAlreadyRegisteredAddBeanDefinition() {
|
||||
String beanName = "beancp-" + BeanConfigurationProperties.class.getName();
|
||||
this.registrar.register(BeanConfigurationProperties.class, null, false);
|
||||
this.registrar.register(BeanConfigurationProperties.class);
|
||||
BeanDefinition definition = this.registry.getBeanDefinition(beanName);
|
||||
assertThat(definition).isNotNull();
|
||||
assertThat(definition.getBeanClassName()).isEqualTo(BeanConfigurationProperties.class.getName());
|
||||
@ -53,7 +52,7 @@ class ConfigurationPropertiesBeanRegistrarTests {
|
||||
void registerWhenAlreadyContainsNameDoesNotReplace() {
|
||||
String beanName = "beancp-" + BeanConfigurationProperties.class.getName();
|
||||
this.registry.registerBeanDefinition(beanName, new GenericBeanDefinition());
|
||||
this.registrar.register(BeanConfigurationProperties.class, null, false);
|
||||
this.registrar.register(BeanConfigurationProperties.class);
|
||||
BeanDefinition definition = this.registry.getBeanDefinition(beanName);
|
||||
assertThat(definition).isNotNull();
|
||||
assertThat(definition.getBeanClassName()).isNull();
|
||||
@ -62,42 +61,24 @@ class ConfigurationPropertiesBeanRegistrarTests {
|
||||
@Test
|
||||
void registerWhenNoAnnotationThrowsException() {
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> this.registrar.register(NoAnnotationConfigurationProperties.class, null, false))
|
||||
.isThrownBy(() -> this.registrar.register(NoAnnotationConfigurationProperties.class))
|
||||
.withMessageContaining("No ConfigurationProperties annotation found");
|
||||
}
|
||||
|
||||
@Test
|
||||
void registerWhenValueObjectRegistersValueObjectBeanDefinition() {
|
||||
String beanName = "valuecp-" + ValueObjectConfigurationProperties.class.getName();
|
||||
this.registrar.register(ValueObjectConfigurationProperties.class, null, false);
|
||||
this.registrar.register(ValueObjectConfigurationProperties.class);
|
||||
BeanDefinition definition = this.registry.getBeanDefinition(beanName);
|
||||
assertThat(definition).isInstanceOf(ConfigurationPropertiesValueObjectBeanDefinition.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void registerWhenNotValueObjectRegistersConfigurationPropertiesBeanDefinition() {
|
||||
void registerWhenNotValueObjectRegistersGenericBeanDefinition() {
|
||||
String beanName = MultiConstructorBeanConfigurationProperties.class.getName();
|
||||
this.registrar.register(MultiConstructorBeanConfigurationProperties.class, null, false);
|
||||
this.registrar.register(MultiConstructorBeanConfigurationProperties.class);
|
||||
BeanDefinition definition = this.registry.getBeanDefinition(beanName);
|
||||
assertThat(definition).isExactlyInstanceOf(ConfigurationPropertiesBeanDefinition.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void registerWhenDeduceBindConstructorRegistersValueObjectBeanDefinition() {
|
||||
String beanName = DeducedValueObjectConfigurationProperties.class.getName();
|
||||
MergedAnnotation<ConfigurationProperties> annotation = MergedAnnotation.of(ConfigurationProperties.class);
|
||||
this.registrar.register(DeducedValueObjectConfigurationProperties.class, annotation, true);
|
||||
BeanDefinition definition = this.registry.getBeanDefinition(beanName);
|
||||
assertThat(definition).isExactlyInstanceOf(ConfigurationPropertiesValueObjectBeanDefinition.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void registerWhenDeduceBindConstructorRegistersJavaBeanObjectBeanDefinition() {
|
||||
String beanName = DeducedJavaBeanConfigurationProperties.class.getName();
|
||||
MergedAnnotation<ConfigurationProperties> annotation = MergedAnnotation.of(ConfigurationProperties.class);
|
||||
this.registrar.register(DeducedJavaBeanConfigurationProperties.class, annotation, true);
|
||||
BeanDefinition definition = this.registry.getBeanDefinition(beanName);
|
||||
assertThat(definition).isExactlyInstanceOf(ConfigurationPropertiesBeanDefinition.class);
|
||||
assertThat(definition).isInstanceOf(GenericBeanDefinition.class);
|
||||
}
|
||||
|
||||
@ConfigurationProperties(prefix = "beancp")
|
||||
@ -129,15 +110,4 @@ class ConfigurationPropertiesBeanRegistrarTests {
|
||||
|
||||
}
|
||||
|
||||
static class DeducedValueObjectConfigurationProperties {
|
||||
|
||||
DeducedValueObjectConfigurationProperties(String name) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class DeducedJavaBeanConfigurationProperties {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* 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.
|
||||
@ -30,7 +30,6 @@ import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.ImportSelector;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.annotation.MergedAnnotation;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
@ -203,8 +202,8 @@ class ConfigurationPropertiesBeanTests {
|
||||
|
||||
@Test
|
||||
void forValueObjectReturnsBean() {
|
||||
ConfigurationPropertiesBean propertiesBean = ConfigurationPropertiesBean.forValueObject(
|
||||
ConstructorBindingOnConstructor.class, "valueObjectBean", MergedAnnotation.missing(), false);
|
||||
ConfigurationPropertiesBean propertiesBean = ConfigurationPropertiesBean
|
||||
.forValueObject(ConstructorBindingOnConstructor.class, "valueObjectBean");
|
||||
assertThat(propertiesBean.getName()).isEqualTo("valueObjectBean");
|
||||
assertThat(propertiesBean.getInstance()).isNull();
|
||||
assertThat(propertiesBean.getType()).isEqualTo(ConstructorBindingOnConstructor.class);
|
||||
@ -214,34 +213,17 @@ class ConfigurationPropertiesBeanTests {
|
||||
assertThat(target.getType()).isEqualTo(ResolvableType.forClass(ConstructorBindingOnConstructor.class));
|
||||
assertThat(target.getValue()).isNull();
|
||||
assertThat(ConfigurationPropertiesBindConstructorProvider.INSTANCE
|
||||
.getBindConstructor(ConstructorBindingOnConstructor.class, false, false)).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void forValueObjectWhenDeduceConstructorReturnsBean() {
|
||||
ConfigurationPropertiesBean propertiesBean = ConfigurationPropertiesBean
|
||||
.forValueObject(DeducedConstructorBinding.class, "valueObjectBean", MergedAnnotation.missing(), true);
|
||||
assertThat(propertiesBean.getName()).isEqualTo("valueObjectBean");
|
||||
assertThat(propertiesBean.getInstance()).isNull();
|
||||
assertThat(propertiesBean.getType()).isEqualTo(DeducedConstructorBinding.class);
|
||||
assertThat(propertiesBean.getBindMethod()).isEqualTo(BindMethod.VALUE_OBJECT);
|
||||
assertThat(propertiesBean.getAnnotation()).isNotNull();
|
||||
Bindable<?> target = propertiesBean.asBindTarget();
|
||||
assertThat(target.getType()).isEqualTo(ResolvableType.forClass(DeducedConstructorBinding.class));
|
||||
assertThat(target.getValue()).isNull();
|
||||
assertThat(ConfigurationPropertiesBindConstructorProvider.INSTANCE
|
||||
.getBindConstructor(ConstructorBindingOnConstructor.class, false, false)).isNotNull();
|
||||
.getBindConstructor(ConstructorBindingOnConstructor.class, false)).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void forValueObjectWhenJavaBeanBindTypeThrowsException() {
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> ConfigurationPropertiesBean.forValueObject(AnnotatedBean.class, "annotatedBean",
|
||||
MergedAnnotation.missing(), false))
|
||||
.isThrownBy(() -> ConfigurationPropertiesBean.forValueObject(AnnotatedBean.class, "annotatedBean"))
|
||||
.withMessage("Bean 'annotatedBean' is not a @ConfigurationProperties value object");
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> ConfigurationPropertiesBean.forValueObject(NonAnnotatedBean.class, "nonAnnotatedBean",
|
||||
MergedAnnotation.missing(), false))
|
||||
.isThrownBy(
|
||||
() -> ConfigurationPropertiesBean.forValueObject(NonAnnotatedBean.class, "nonAnnotatedBean"))
|
||||
.withMessage("Bean 'nonAnnotatedBean' is not a @ConfigurationProperties value object");
|
||||
|
||||
}
|
||||
@ -259,7 +241,7 @@ class ConfigurationPropertiesBeanTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void bindTypeForTypeWhenConstructorBindingOnConstructorReturnsValueObject() {
|
||||
void bindTypeForTypeWhenNoConstructorBindingOnConstructorReturnsValueObject() {
|
||||
BindMethod bindType = BindMethod.forType(ConstructorBindingOnConstructor.class);
|
||||
assertThat(bindType).isEqualTo(BindMethod.VALUE_OBJECT);
|
||||
}
|
||||
@ -272,18 +254,6 @@ class ConfigurationPropertiesBeanTests {
|
||||
+ " has more than one @ConstructorBinding constructor");
|
||||
}
|
||||
|
||||
@Test
|
||||
void bindTypeForTypeWhenDeducedConstructorBindingOnValueObjectReturnsValueObject() {
|
||||
BindMethod bindType = BindMethod.forType(DeducedConstructorBinding.class, true);
|
||||
assertThat(bindType).isEqualTo(BindMethod.VALUE_OBJECT);
|
||||
}
|
||||
|
||||
@Test
|
||||
void bindTypeForTypeWhenDeducedConstructorBindingOnJavaBeanReturnsJavABean() {
|
||||
BindMethod bindType = BindMethod.forType(NonAnnotatedBean.class, true);
|
||||
assertThat(bindType).isEqualTo(BindMethod.JAVA_BEAN);
|
||||
}
|
||||
|
||||
private void get(Class<?> configuration, String beanName, ThrowingConsumer<ConfigurationPropertiesBean> consumer)
|
||||
throws Throwable {
|
||||
get(configuration, beanName, true, consumer);
|
||||
@ -504,14 +474,6 @@ class ConfigurationPropertiesBeanTests {
|
||||
|
||||
}
|
||||
|
||||
@ConfigurationProperties
|
||||
static class DeducedConstructorBinding {
|
||||
|
||||
DeducedConstructorBinding(String name) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(NonAnnotatedBeanConfigurationImportSelector.class)
|
||||
static class NonAnnotatedBeanImportConfiguration {
|
||||
|
@ -21,6 +21,7 @@ import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.GenericBeanDefinition;
|
||||
import org.springframework.boot.context.properties.scan.combined.c.CombinedConfiguration;
|
||||
import org.springframework.boot.context.properties.scan.combined.d.OtherCombinedConfiguration;
|
||||
import org.springframework.boot.context.properties.scan.valid.ConfigurationPropertiesScanConfiguration;
|
||||
@ -52,8 +53,8 @@ class ConfigurationPropertiesScanRegistrarTests {
|
||||
"foo-org.springframework.boot.context.properties.scan.valid.ConfigurationPropertiesScanConfiguration$FooProperties");
|
||||
BeanDefinition barDefinition = this.beanFactory.getBeanDefinition(
|
||||
"bar-org.springframework.boot.context.properties.scan.valid.ConfigurationPropertiesScanConfiguration$BarProperties");
|
||||
assertThat(bingDefinition).isExactlyInstanceOf(ConfigurationPropertiesBeanDefinition.class);
|
||||
assertThat(fooDefinition).isExactlyInstanceOf(ConfigurationPropertiesBeanDefinition.class);
|
||||
assertThat(bingDefinition).isExactlyInstanceOf(GenericBeanDefinition.class);
|
||||
assertThat(fooDefinition).isExactlyInstanceOf(GenericBeanDefinition.class);
|
||||
assertThat(barDefinition).isExactlyInstanceOf(ConfigurationPropertiesValueObjectBeanDefinition.class);
|
||||
}
|
||||
|
||||
@ -65,7 +66,7 @@ class ConfigurationPropertiesScanRegistrarTests {
|
||||
getAnnotationMetadata(ConfigurationPropertiesScanConfiguration.TestConfiguration.class), beanFactory);
|
||||
BeanDefinition fooDefinition = beanFactory.getBeanDefinition(
|
||||
"foo-org.springframework.boot.context.properties.scan.valid.ConfigurationPropertiesScanConfiguration$FooProperties");
|
||||
assertThat(fooDefinition).isExactlyInstanceOf(ConfigurationPropertiesBeanDefinition.class);
|
||||
assertThat(fooDefinition).isExactlyInstanceOf(GenericBeanDefinition.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -84,11 +85,11 @@ class ConfigurationPropertiesScanRegistrarTests {
|
||||
"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(ConfigurationPropertiesBeanDefinition.class);
|
||||
assertThat(aDefinition).isExactlyInstanceOf(GenericBeanDefinition.class);
|
||||
// Constructor injection
|
||||
assertThat(bFirstDefinition).isExactlyInstanceOf(ConfigurationPropertiesValueObjectBeanDefinition.class);
|
||||
// Post-processing injection
|
||||
assertThat(bSecondDefinition).isExactlyInstanceOf(ConfigurationPropertiesBeanDefinition.class);
|
||||
assertThat(bSecondDefinition).isExactlyInstanceOf(GenericBeanDefinition.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* 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.
|
||||
@ -22,6 +22,7 @@ import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.GenericBeanDefinition;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@ -51,11 +52,11 @@ class EnableConfigurationPropertiesRegistrarTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void typeWithDefaultConstructorShouldRegisterConfigurationPropertiesBeanDefinition() throws Exception {
|
||||
void typeWithDefaultConstructorShouldRegisterGenericBeanDefinition() throws Exception {
|
||||
register(TestConfiguration.class);
|
||||
BeanDefinition beanDefinition = this.beanFactory
|
||||
.getBeanDefinition("foo-" + getClass().getName() + "$FooProperties");
|
||||
assertThat(beanDefinition).isExactlyInstanceOf(ConfigurationPropertiesBeanDefinition.class);
|
||||
assertThat(beanDefinition).isExactlyInstanceOf(GenericBeanDefinition.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -67,11 +68,11 @@ class EnableConfigurationPropertiesRegistrarTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void typeWithMultipleConstructorsShouldRegisterConfigurationPropertiesBeanDefinition() throws Exception {
|
||||
void typeWithMultipleConstructorsShouldRegisterGenericBeanDefinition() throws Exception {
|
||||
register(TestConfiguration.class);
|
||||
BeanDefinition beanDefinition = this.beanFactory
|
||||
.getBeanDefinition("bing-" + getClass().getName() + "$BingProperties");
|
||||
assertThat(beanDefinition).isExactlyInstanceOf(ConfigurationPropertiesBeanDefinition.class);
|
||||
assertThat(beanDefinition).isExactlyInstanceOf(GenericBeanDefinition.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1,182 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2020 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.context.properties;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.context.support.TestPropertySourceUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
|
||||
/**
|
||||
* Tests for {@link ImportAsConfigurationPropertiesBean}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class ImportAsConfigurationPropertiesBeanTests {
|
||||
|
||||
@Test
|
||||
void importJavaBean() {
|
||||
try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {
|
||||
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(context.getEnvironment(), "test.name=spring");
|
||||
context.register(JavaBeanConfig.class);
|
||||
context.refresh();
|
||||
assertThat(context.getBean(JavaBean.class).getName()).isEqualTo("spring");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void importValueObject() {
|
||||
try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {
|
||||
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(context.getEnvironment(), "test.value=spring");
|
||||
context.register(ValueObjectConfig.class);
|
||||
context.refresh();
|
||||
assertThat(context.getBean(ValueObject.class).getValue()).isEqualTo("spring");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void importMultiConstructorValueObjectFails() {
|
||||
try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {
|
||||
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(context.getEnvironment(), "test.name=spring");
|
||||
context.register(MultiConstructorValueObjectConfig.class);
|
||||
assertThatIllegalStateException().isThrownBy(context::refresh).havingCause()
|
||||
.withMessageContaining("Unable to deduce");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void importMultipleTypes() {
|
||||
try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {
|
||||
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(context.getEnvironment(), "test.name=spring",
|
||||
"test.value=boot");
|
||||
context.register(ImportMultipleTypesConfig.class);
|
||||
context.refresh();
|
||||
assertThat(context.getBean(JavaBean.class).getName()).isEqualTo("spring");
|
||||
assertThat(context.getBean(ValueObject.class).getValue()).isEqualTo("boot");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void importRepeatedAnnotations() {
|
||||
try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {
|
||||
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(context.getEnvironment(), "jb.name=spring",
|
||||
"vo.value=boot");
|
||||
context.register(ImportRepeatedAnnotationsConfig.class);
|
||||
context.refresh();
|
||||
assertThat(context.getBean(JavaBean.class).getName()).isEqualTo("spring");
|
||||
assertThat(context.getBean(ValueObject.class).getValue()).isEqualTo("boot");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void importAnnoatedBeanConfig() {
|
||||
try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {
|
||||
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(context.getEnvironment(), "onbean.name=spring");
|
||||
context.register(ImportAnnotatedClassConfig.class);
|
||||
context.refresh();
|
||||
assertThat(context.getBean(JavaBean.class).getName()).isEqualTo("spring");
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ImportAsConfigurationPropertiesBean(prefix = "test", type = JavaBean.class)
|
||||
static class JavaBeanConfig {
|
||||
|
||||
}
|
||||
|
||||
static class JavaBean {
|
||||
|
||||
private String name;
|
||||
|
||||
String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ImportAsConfigurationPropertiesBean(prefix = "test", type = ValueObject.class)
|
||||
static class ValueObjectConfig {
|
||||
|
||||
}
|
||||
|
||||
static class ValueObject {
|
||||
|
||||
private final String value;
|
||||
|
||||
ValueObject(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ImportAsConfigurationPropertiesBean(prefix = "test", type = MultiConstructorValueObject.class)
|
||||
static class MultiConstructorValueObjectConfig {
|
||||
|
||||
}
|
||||
|
||||
static class MultiConstructorValueObject {
|
||||
|
||||
MultiConstructorValueObject() {
|
||||
}
|
||||
|
||||
MultiConstructorValueObject(String name) {
|
||||
}
|
||||
|
||||
MultiConstructorValueObject(String name, int age) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ImportAsConfigurationPropertiesBean(type = { ValueObject.class, JavaBean.class }, prefix = "test")
|
||||
static class ImportMultipleTypesConfig {
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ImportAsConfigurationPropertiesBean(type = ValueObject.class, prefix = "vo")
|
||||
@ImportAsConfigurationPropertiesBean(type = JavaBean.class, prefix = "jb")
|
||||
static class ImportRepeatedAnnotationsConfig {
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ImportAsConfigurationPropertiesBean(AnnotatedJavaBean.class)
|
||||
static class ImportAnnotatedClassConfig {
|
||||
|
||||
}
|
||||
|
||||
@ConfigurationProperties(prefix = "onbean")
|
||||
static class AnnotatedJavaBean extends JavaBean {
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -139,19 +139,6 @@ class BindableTests {
|
||||
assertThat(Bindable.of(String.class).withAnnotations(annotation).getAnnotation(Bean.class)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void withAttributeShouldSetAttribute() {
|
||||
Bindable<String> bindable = Bindable.of(String.class);
|
||||
Bindable<String> withOne = bindable.withAttribute("one", 1);
|
||||
Bindable<String> withOneAndTwo = withOne.withAttribute("two", 2);
|
||||
assertThat(bindable.getAttribute("one")).isNull();
|
||||
assertThat(bindable.getAttribute("two")).isNull();
|
||||
assertThat(withOne.getAttribute("one")).isEqualTo(1);
|
||||
assertThat(withOne.getAttribute("two")).isNull();
|
||||
assertThat(withOneAndTwo.getAttribute("one")).isEqualTo(1);
|
||||
assertThat(withOneAndTwo.getAttribute("two")).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void toStringShouldShowDetails() {
|
||||
Annotation annotation = AnnotationUtils.synthesizeAnnotation(TestAnnotation.class);
|
||||
@ -167,10 +154,9 @@ class BindableTests {
|
||||
Bindable<String> bindable1 = Bindable.of(String.class).withExistingValue("foo").withAnnotations(annotation);
|
||||
Bindable<String> bindable2 = Bindable.of(String.class).withExistingValue("foo").withAnnotations(annotation);
|
||||
Bindable<String> bindable3 = Bindable.of(String.class).withExistingValue("fof").withAnnotations(annotation);
|
||||
Bindable<String> bindable4 = Bindable.of(String.class).withExistingValue("foo").withAnnotations(annotation)
|
||||
.withAttribute("bar", "bar");
|
||||
assertThat(bindable1.hashCode()).isEqualTo(bindable2.hashCode());
|
||||
assertThat(bindable1).isEqualTo(bindable1).isEqualTo(bindable2).isEqualTo(bindable3).isNotEqualTo(bindable4);
|
||||
assertThat(bindable1).isEqualTo(bindable1).isEqualTo(bindable2);
|
||||
assertThat(bindable1).isEqualTo(bindable3);
|
||||
}
|
||||
|
||||
@Test // gh-18218
|
||||
|
@ -3,6 +3,7 @@ package org.springframework.boot.context.properties
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory
|
||||
import org.springframework.beans.factory.support.GenericBeanDefinition
|
||||
import org.springframework.core.type.AnnotationMetadata
|
||||
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory
|
||||
|
||||
@ -20,15 +21,15 @@ class KotlinConfigurationPropertiesBeanRegistrarTests {
|
||||
|
||||
@Test
|
||||
fun `type with default constructor should register generic bean definition`() {
|
||||
this.registrar.register(FooProperties::class.java, null, false)
|
||||
this.registrar.register(FooProperties::class.java)
|
||||
val beanDefinition = this.beanFactory.getBeanDefinition(
|
||||
"foo-org.springframework.boot.context.properties.KotlinConfigurationPropertiesBeanRegistrarTests\$FooProperties")
|
||||
assertThat(beanDefinition).isExactlyInstanceOf(ConfigurationPropertiesBeanDefinition::class.java)
|
||||
assertThat(beanDefinition).isExactlyInstanceOf(GenericBeanDefinition::class.java)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `type with primary constructor and no autowired should register configuration properties bean definition`() {
|
||||
this.registrar.register(BarProperties::class.java, null, false)
|
||||
this.registrar.register(BarProperties::class.java)
|
||||
val beanDefinition = this.beanFactory.getBeanDefinition(
|
||||
"bar-org.springframework.boot.context.properties.KotlinConfigurationPropertiesBeanRegistrarTests\$BarProperties")
|
||||
assertThat(beanDefinition).isExactlyInstanceOf(
|
||||
@ -37,10 +38,10 @@ class KotlinConfigurationPropertiesBeanRegistrarTests {
|
||||
|
||||
@Test
|
||||
fun `type with no primary constructor should register generic bean definition`() {
|
||||
this.registrar.register(BingProperties::class.java, null, false)
|
||||
this.registrar.register(BingProperties::class.java)
|
||||
val beanDefinition = this.beanFactory.getBeanDefinition(
|
||||
"bing-org.springframework.boot.context.properties.KotlinConfigurationPropertiesBeanRegistrarTests\$BingProperties")
|
||||
assertThat(beanDefinition).isExactlyInstanceOf(ConfigurationPropertiesBeanDefinition::class.java)
|
||||
assertThat(beanDefinition).isExactlyInstanceOf(GenericBeanDefinition::class.java)
|
||||
}
|
||||
|
||||
@ConfigurationProperties(prefix = "foo")
|
||||
|
Loading…
Reference in New Issue
Block a user