Add metadata support for immutable ConfigurationProperties type
Closes gh-16071
This commit is contained in:
@@ -43,6 +43,9 @@ import org.springframework.boot.configurationsample.specific.InnerClassHierarchi
|
||||
import org.springframework.boot.configurationsample.specific.InnerClassProperties;
|
||||
import org.springframework.boot.configurationsample.specific.InnerClassRootConfig;
|
||||
import org.springframework.boot.configurationsample.specific.InvalidAccessorProperties;
|
||||
import org.springframework.boot.configurationsample.specific.InvalidDefaultValueCharacterProperties;
|
||||
import org.springframework.boot.configurationsample.specific.InvalidDefaultValueFloatingPointProperties;
|
||||
import org.springframework.boot.configurationsample.specific.InvalidDefaultValueNumberProperties;
|
||||
import org.springframework.boot.configurationsample.specific.InvalidDoubleRegistrationProperties;
|
||||
import org.springframework.boot.configurationsample.specific.SimplePojo;
|
||||
import org.springframework.boot.configurationsample.specific.StaticAccessor;
|
||||
@@ -385,4 +388,26 @@ public class ConfigurationMetadataAnnotationProcessorTests
|
||||
.withMessageContaining("Compilation failed");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorParameterPropertyWithInvalidDefaultValueOnNumber() {
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> compile(InvalidDefaultValueNumberProperties.class))
|
||||
.withMessageContaining("Compilation failed");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorParameterPropertyWithInvalidDefaultValueOnFloatingPoint() {
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(
|
||||
() -> compile(InvalidDefaultValueFloatingPointProperties.class))
|
||||
.withMessageContaining("Compilation failed");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorParameterPropertyWithInvalidDefaultValueOnCharacter() {
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> compile(InvalidDefaultValueCharacterProperties.class))
|
||||
.withMessageContaining("Compilation failed");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,318 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.configurationprocessor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.element.VariableElement;
|
||||
import javax.lang.model.util.ElementFilter;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.configurationsample.immutable.ImmutableCollectionProperties;
|
||||
import org.springframework.boot.configurationsample.immutable.ImmutableInnerClassProperties;
|
||||
import org.springframework.boot.configurationsample.immutable.ImmutablePrimitiveProperties;
|
||||
import org.springframework.boot.configurationsample.immutable.ImmutablePrimitiveWithDefaultsProperties;
|
||||
import org.springframework.boot.configurationsample.immutable.ImmutablePrimitiveWrapperWithDefaultsProperties;
|
||||
import org.springframework.boot.configurationsample.immutable.ImmutableSimpleProperties;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link ConstructorParameterPropertyDescriptor}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public class ConstructorParameterPropertyDescriptorTests extends PropertyDescriptorTests {
|
||||
|
||||
@Test
|
||||
public void constructorParameterSimpleProperty() throws IOException {
|
||||
process(ImmutableSimpleProperties.class, (roundEnv, metadataEnv) -> {
|
||||
TypeElement ownerElement = roundEnv
|
||||
.getRootElement(ImmutableSimpleProperties.class);
|
||||
ConstructorParameterPropertyDescriptor property = createPropertyDescriptor(
|
||||
ownerElement, "theName");
|
||||
assertThat(property.getName()).isEqualTo("theName");
|
||||
assertThat(property.getSource()).hasToString("theName");
|
||||
assertThat(property.getGetter().getSimpleName()).hasToString("getTheName");
|
||||
assertThat(property.isProperty(metadataEnv)).isTrue();
|
||||
assertThat(property.isNested(metadataEnv)).isFalse();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorParameterNestedPropertySameClass() throws IOException {
|
||||
process(ImmutableInnerClassProperties.class, (roundEnv, metadataEnv) -> {
|
||||
TypeElement ownerElement = roundEnv
|
||||
.getRootElement(ImmutableInnerClassProperties.class);
|
||||
ConstructorParameterPropertyDescriptor property = createPropertyDescriptor(
|
||||
ownerElement, "first");
|
||||
assertThat(property.getName()).isEqualTo("first");
|
||||
assertThat(property.getSource()).hasToString("first");
|
||||
assertThat(property.getGetter().getSimpleName()).hasToString("getFirst");
|
||||
assertThat(property.isProperty(metadataEnv)).isFalse();
|
||||
assertThat(property.isNested(metadataEnv)).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorParameterNestedPropertyWithAnnotation() throws IOException {
|
||||
process(ImmutableInnerClassProperties.class, (roundEnv, metadataEnv) -> {
|
||||
TypeElement ownerElement = roundEnv
|
||||
.getRootElement(ImmutableInnerClassProperties.class);
|
||||
ConstructorParameterPropertyDescriptor property = createPropertyDescriptor(
|
||||
ownerElement, "third");
|
||||
assertThat(property.getName()).isEqualTo("third");
|
||||
assertThat(property.getSource()).hasToString("third");
|
||||
assertThat(property.getGetter().getSimpleName()).hasToString("getThird");
|
||||
assertThat(property.isProperty(metadataEnv)).isFalse();
|
||||
assertThat(property.isNested(metadataEnv)).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorParameterSimplePropertyWithNoAccessorShouldBeExposed()
|
||||
throws IOException {
|
||||
process(ImmutableSimpleProperties.class, (roundEnv, metadataEnv) -> {
|
||||
TypeElement ownerElement = roundEnv
|
||||
.getRootElement(ImmutableSimpleProperties.class);
|
||||
ConstructorParameterPropertyDescriptor property = createPropertyDescriptor(
|
||||
ownerElement, "counter");
|
||||
assertThat(property.getName()).isEqualTo("counter");
|
||||
assertThat(property.getSource()).hasToString("counter");
|
||||
assertThat(property.getGetter()).isNull();
|
||||
assertThat(property.isProperty(metadataEnv)).isTrue();
|
||||
assertThat(property.isNested(metadataEnv)).isFalse();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorParameterMetadataSimpleProperty() throws IOException {
|
||||
process(ImmutableSimpleProperties.class, (roundEnv, metadataEnv) -> {
|
||||
TypeElement ownerElement = roundEnv
|
||||
.getRootElement(ImmutableSimpleProperties.class);
|
||||
ConstructorParameterPropertyDescriptor property = createPropertyDescriptor(
|
||||
ownerElement, "counter");
|
||||
assertItemMetadata(metadataEnv, property).isProperty().hasName("test.counter")
|
||||
.hasType(Long.class).hasSourceType(ImmutableSimpleProperties.class)
|
||||
.hasNoDescription().isNotDeprecated();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorParameterMetadataNestedGroup() throws IOException {
|
||||
process(ImmutableInnerClassProperties.class, (roundEnv, metadataEnv) -> {
|
||||
TypeElement ownerElement = roundEnv
|
||||
.getRootElement(ImmutableInnerClassProperties.class);
|
||||
ConstructorParameterPropertyDescriptor property = createPropertyDescriptor(
|
||||
ownerElement, "first");
|
||||
assertItemMetadata(metadataEnv, property).isGroup().hasName("test.first")
|
||||
.hasType(
|
||||
"org.springframework.boot.configurationsample.immutable.ImmutableInnerClassProperties$Foo")
|
||||
.hasSourceType(ImmutableInnerClassProperties.class)
|
||||
.hasSourceMethod("getFirst()").hasNoDescription().isNotDeprecated();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorParameterDeprecatedPropertyOnGetter() throws IOException {
|
||||
process(ImmutableSimpleProperties.class, (roundEnv, metadataEnv) -> {
|
||||
TypeElement ownerElement = roundEnv
|
||||
.getRootElement(ImmutableSimpleProperties.class);
|
||||
ExecutableElement getter = getMethod(ownerElement, "isFlag");
|
||||
VariableElement field = getField(ownerElement, "flag");
|
||||
VariableElement constructorParameter = getConstructorParameter(ownerElement,
|
||||
"flag");
|
||||
ConstructorParameterPropertyDescriptor property = new ConstructorParameterPropertyDescriptor(
|
||||
ownerElement, null, constructorParameter, "flag", field.asType(),
|
||||
field, getter, null);
|
||||
assertItemMetadata(metadataEnv, property).isProperty()
|
||||
.isDeprecatedWithNoInformation();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorParameterPropertyWithDescription() throws IOException {
|
||||
process(ImmutableSimpleProperties.class, (roundEnv, metadataEnv) -> {
|
||||
TypeElement ownerElement = roundEnv
|
||||
.getRootElement(ImmutableSimpleProperties.class);
|
||||
ConstructorParameterPropertyDescriptor property = createPropertyDescriptor(
|
||||
ownerElement, "theName");
|
||||
assertItemMetadata(metadataEnv, property).isProperty()
|
||||
.hasDescription("The name of this simple properties.");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorParameterPropertyWithDefaultValue() throws IOException {
|
||||
process(ImmutableSimpleProperties.class, (roundEnv, metadataEnv) -> {
|
||||
TypeElement ownerElement = roundEnv
|
||||
.getRootElement(ImmutableSimpleProperties.class);
|
||||
ConstructorParameterPropertyDescriptor property = createPropertyDescriptor(
|
||||
ownerElement, "theName");
|
||||
assertItemMetadata(metadataEnv, property).isProperty()
|
||||
.hasDefaultValue("boot");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorParameterPropertyWithPrimitiveTypes() throws IOException {
|
||||
process(ImmutablePrimitiveProperties.class, (roundEnv, metadataEnv) -> {
|
||||
TypeElement ownerElement = roundEnv
|
||||
.getRootElement(ImmutablePrimitiveProperties.class);
|
||||
assertItemMetadata(metadataEnv,
|
||||
createPropertyDescriptor(ownerElement, "flag"))
|
||||
.hasDefaultValue(false);
|
||||
assertItemMetadata(metadataEnv,
|
||||
createPropertyDescriptor(ownerElement, "octet")).hasDefaultValue(0);
|
||||
assertItemMetadata(metadataEnv,
|
||||
createPropertyDescriptor(ownerElement, "letter"))
|
||||
.hasDefaultValue(null);
|
||||
assertItemMetadata(metadataEnv,
|
||||
createPropertyDescriptor(ownerElement, "number")).hasDefaultValue(0);
|
||||
assertItemMetadata(metadataEnv,
|
||||
createPropertyDescriptor(ownerElement, "counter")).hasDefaultValue(0);
|
||||
assertItemMetadata(metadataEnv,
|
||||
createPropertyDescriptor(ownerElement, "value")).hasDefaultValue(0L);
|
||||
assertItemMetadata(metadataEnv,
|
||||
createPropertyDescriptor(ownerElement, "percentage"))
|
||||
.hasDefaultValue(0);
|
||||
assertItemMetadata(metadataEnv,
|
||||
createPropertyDescriptor(ownerElement, "ratio")).hasDefaultValue(0D);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorParameterPropertyWithPrimitiveTypesAndDefaultValues()
|
||||
throws IOException {
|
||||
process(ImmutablePrimitiveWithDefaultsProperties.class,
|
||||
(roundEnv, metadataEnv) -> {
|
||||
TypeElement ownerElement = roundEnv.getRootElement(
|
||||
ImmutablePrimitiveWithDefaultsProperties.class);
|
||||
assertItemMetadata(metadataEnv,
|
||||
createPropertyDescriptor(ownerElement, "flag"))
|
||||
.hasDefaultValue(true);
|
||||
assertItemMetadata(metadataEnv,
|
||||
createPropertyDescriptor(ownerElement, "octet"))
|
||||
.hasDefaultValue(120);
|
||||
assertItemMetadata(metadataEnv,
|
||||
createPropertyDescriptor(ownerElement, "letter"))
|
||||
.hasDefaultValue("a");
|
||||
assertItemMetadata(metadataEnv,
|
||||
createPropertyDescriptor(ownerElement, "number"))
|
||||
.hasDefaultValue(1000);
|
||||
assertItemMetadata(metadataEnv,
|
||||
createPropertyDescriptor(ownerElement, "counter"))
|
||||
.hasDefaultValue(42);
|
||||
assertItemMetadata(metadataEnv,
|
||||
createPropertyDescriptor(ownerElement, "value"))
|
||||
.hasDefaultValue(2000);
|
||||
assertItemMetadata(metadataEnv,
|
||||
createPropertyDescriptor(ownerElement, "percentage"))
|
||||
.hasDefaultValue(0.5);
|
||||
assertItemMetadata(metadataEnv,
|
||||
createPropertyDescriptor(ownerElement, "ratio"))
|
||||
.hasDefaultValue(42.42);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorParameterPropertyWithPrimitiveWrapperTypesAndDefaultValues()
|
||||
throws IOException {
|
||||
process(ImmutablePrimitiveWrapperWithDefaultsProperties.class,
|
||||
(roundEnv, metadataEnv) -> {
|
||||
TypeElement ownerElement = roundEnv.getRootElement(
|
||||
ImmutablePrimitiveWrapperWithDefaultsProperties.class);
|
||||
assertItemMetadata(metadataEnv,
|
||||
createPropertyDescriptor(ownerElement, "flag"))
|
||||
.hasDefaultValue(true);
|
||||
assertItemMetadata(metadataEnv,
|
||||
createPropertyDescriptor(ownerElement, "octet"))
|
||||
.hasDefaultValue(120);
|
||||
assertItemMetadata(metadataEnv,
|
||||
createPropertyDescriptor(ownerElement, "letter"))
|
||||
.hasDefaultValue("a");
|
||||
assertItemMetadata(metadataEnv,
|
||||
createPropertyDescriptor(ownerElement, "number"))
|
||||
.hasDefaultValue(1000);
|
||||
assertItemMetadata(metadataEnv,
|
||||
createPropertyDescriptor(ownerElement, "counter"))
|
||||
.hasDefaultValue(42);
|
||||
assertItemMetadata(metadataEnv,
|
||||
createPropertyDescriptor(ownerElement, "value"))
|
||||
.hasDefaultValue(2000);
|
||||
assertItemMetadata(metadataEnv,
|
||||
createPropertyDescriptor(ownerElement, "percentage"))
|
||||
.hasDefaultValue(0.5);
|
||||
assertItemMetadata(metadataEnv,
|
||||
createPropertyDescriptor(ownerElement, "ratio"))
|
||||
.hasDefaultValue(42.42);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorParameterPropertyWithCollectionTypesAndDefaultValues()
|
||||
throws IOException {
|
||||
process(ImmutableCollectionProperties.class, (roundEnv, metadataEnv) -> {
|
||||
TypeElement ownerElement = roundEnv
|
||||
.getRootElement(ImmutableCollectionProperties.class);
|
||||
assertItemMetadata(metadataEnv,
|
||||
createPropertyDescriptor(ownerElement, "names"))
|
||||
.hasDefaultValue(null);
|
||||
assertItemMetadata(metadataEnv,
|
||||
createPropertyDescriptor(ownerElement, "flags"))
|
||||
.hasDefaultValue(Arrays.asList(true, false));
|
||||
assertItemMetadata(metadataEnv,
|
||||
createPropertyDescriptor(ownerElement, "durations"))
|
||||
.hasDefaultValue(Arrays.asList("10s", "1m", "1h"));
|
||||
});
|
||||
}
|
||||
|
||||
protected ConstructorParameterPropertyDescriptor createPropertyDescriptor(
|
||||
TypeElement ownerElement, String name) {
|
||||
VariableElement constructorParameter = getConstructorParameter(ownerElement,
|
||||
name);
|
||||
VariableElement field = getField(ownerElement, name);
|
||||
ExecutableElement getter = getMethod(ownerElement,
|
||||
createAccessorMethodName("get", name));
|
||||
ExecutableElement setter = getMethod(ownerElement,
|
||||
createAccessorMethodName("set", name));
|
||||
return new ConstructorParameterPropertyDescriptor(ownerElement, null,
|
||||
constructorParameter, name, field.asType(), field, getter, setter);
|
||||
}
|
||||
|
||||
private VariableElement getConstructorParameter(TypeElement ownerElement,
|
||||
String name) {
|
||||
List<ExecutableElement> constructors = ElementFilter
|
||||
.constructorsIn(ownerElement.getEnclosedElements()).stream()
|
||||
.filter((constructor) -> !constructor.getParameters().isEmpty())
|
||||
.collect(Collectors.toList());
|
||||
if (constructors.size() != 1) {
|
||||
throw new IllegalStateException(
|
||||
"No candidate constructor for " + ownerElement);
|
||||
}
|
||||
return constructors.get(0).getParameters().stream()
|
||||
.filter((parameter) -> parameter.getSimpleName().toString().equals(name))
|
||||
.findFirst().orElse(null);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.configurationprocessor;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata;
|
||||
import org.springframework.boot.configurationprocessor.metadata.Metadata;
|
||||
import org.springframework.boot.configurationsample.immutable.ImmutableSimpleProperties;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Metadata generation tests for immutable properties.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public class ImmutablePropertiesMetadataGenerationTests
|
||||
extends AbstractMetadataGenerationTests {
|
||||
|
||||
@Test
|
||||
public void immutableSimpleProperties() {
|
||||
ConfigurationMetadata metadata = compile(ImmutableSimpleProperties.class);
|
||||
assertThat(metadata).has(Metadata.withGroup("immutable")
|
||||
.fromSource(ImmutableSimpleProperties.class));
|
||||
assertThat(metadata).has(Metadata.withProperty("immutable.the-name", String.class)
|
||||
.fromSource(ImmutableSimpleProperties.class)
|
||||
.withDescription("The name of this simple properties.")
|
||||
.withDefaultValue("boot"));
|
||||
assertThat(metadata).has(Metadata.withProperty("immutable.flag", Boolean.class)
|
||||
.withDefaultValue(false).fromSource(ImmutableSimpleProperties.class)
|
||||
.withDescription("A simple flag.").withDeprecation(null, null));
|
||||
assertThat(metadata).has(Metadata.withProperty("immutable.comparator"));
|
||||
assertThat(metadata).has(Metadata.withProperty("immutable.counter"));
|
||||
assertThat(metadata.getItems()).hasSize(5);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -36,6 +36,7 @@ class MetadataGenerationEnvironmentFactory
|
||||
TestConfigurationMetadataAnnotationProcessor.CONFIGURATION_PROPERTIES_ANNOTATION,
|
||||
TestConfigurationMetadataAnnotationProcessor.NESTED_CONFIGURATION_PROPERTY_ANNOTATION,
|
||||
TestConfigurationMetadataAnnotationProcessor.DEPRECATED_CONFIGURATION_PROPERTY_ANNOTATION,
|
||||
TestConfigurationMetadataAnnotationProcessor.DEFAULT_VALUE_ANNOTATION,
|
||||
TestConfigurationMetadataAnnotationProcessor.ENDPOINT_ANNOTATION,
|
||||
TestConfigurationMetadataAnnotationProcessor.READ_OPERATION_ANNOTATION);
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import org.junit.rules.TemporaryFolder;
|
||||
import org.springframework.boot.configurationprocessor.metadata.ItemMetadata;
|
||||
import org.springframework.boot.configurationprocessor.test.RoundEnvironmentTester;
|
||||
import org.springframework.boot.configurationprocessor.test.TestableAnnotationProcessor;
|
||||
import org.springframework.boot.configurationsample.immutable.ImmutableSimpleProperties;
|
||||
import org.springframework.boot.configurationsample.lombok.LombokExplicitProperties;
|
||||
import org.springframework.boot.configurationsample.lombok.LombokSimpleDataProperties;
|
||||
import org.springframework.boot.configurationsample.lombok.LombokSimpleProperties;
|
||||
@@ -41,6 +42,7 @@ import org.springframework.boot.configurationsample.simple.HierarchicalPropertie
|
||||
import org.springframework.boot.configurationsample.simple.HierarchicalPropertiesGrandparent;
|
||||
import org.springframework.boot.configurationsample.simple.HierarchicalPropertiesParent;
|
||||
import org.springframework.boot.configurationsample.simple.SimpleProperties;
|
||||
import org.springframework.boot.configurationsample.specific.TwoConstructorsExample;
|
||||
import org.springframework.boot.testsupport.compiler.TestCompiler;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -100,6 +102,21 @@ public class PropertyDescriptorResolverTests {
|
||||
"description", "counter", "number", "items")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void propertiesWithConstructorParameters() throws IOException {
|
||||
process(ImmutableSimpleProperties.class,
|
||||
propertyNames((stream) -> assertThat(stream).containsExactly("theName",
|
||||
"flag", "comparator", "counter")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void propertiesWithSeveralConstructors() throws IOException {
|
||||
process(TwoConstructorsExample.class,
|
||||
propertyNames((stream) -> assertThat(stream).containsExactly("name")));
|
||||
process(TwoConstructorsExample.class, properties((stream) -> assertThat(stream)
|
||||
.element(0).isInstanceOf(JavaBeanPropertyDescriptor.class)));
|
||||
}
|
||||
|
||||
private BiConsumer<TypeElement, MetadataGenerationEnvironment> properties(
|
||||
Consumer<Stream<PropertyDescriptor<?>>> stream) {
|
||||
return (element, metadataEnv) -> {
|
||||
|
||||
@@ -47,6 +47,8 @@ public class TestConfigurationMetadataAnnotationProcessor
|
||||
|
||||
public static final String DEPRECATED_CONFIGURATION_PROPERTY_ANNOTATION = "org.springframework.boot.configurationsample.DeprecatedConfigurationProperty";
|
||||
|
||||
public static final String DEFAULT_VALUE_ANNOTATION = "org.springframework.boot.configurationsample.DefaultValue";
|
||||
|
||||
public static final String ENDPOINT_ANNOTATION = "org.springframework.boot.configurationsample.Endpoint";
|
||||
|
||||
public static final String READ_OPERATION_ANNOTATION = "org.springframework.boot.configurationsample.ReadOperation";
|
||||
@@ -74,6 +76,11 @@ public class TestConfigurationMetadataAnnotationProcessor
|
||||
return DEPRECATED_CONFIGURATION_PROPERTY_ANNOTATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String defaultValueAnnotation() {
|
||||
return DEFAULT_VALUE_ANNOTATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String endpointAnnotation() {
|
||||
return ENDPOINT_ANNOTATION;
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.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 @DefaultValue} for testing (removes the need for a
|
||||
* dependency on the real annotation).
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@Target({ ElementType.PARAMETER })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface DefaultValue {
|
||||
|
||||
String[] value();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.configurationsample.immutable;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.configurationsample.DefaultValue;
|
||||
|
||||
/**
|
||||
* Simple immutable properties with collections types and defaults.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public class ImmutableCollectionProperties {
|
||||
|
||||
private final List<String> names;
|
||||
|
||||
private final List<Boolean> flags;
|
||||
|
||||
private final List<Duration> durations;
|
||||
|
||||
public ImmutableCollectionProperties(List<String> names,
|
||||
@DefaultValue({ "true", "false" }) List<Boolean> flags,
|
||||
@DefaultValue({ "10s", "1m", "1h" }) List<Duration> durations) {
|
||||
this.names = names;
|
||||
this.flags = flags;
|
||||
this.durations = durations;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.configurationsample.immutable;
|
||||
|
||||
import org.springframework.boot.configurationsample.NestedConfigurationProperty;
|
||||
import org.springframework.boot.configurationsample.specific.SimplePojo;
|
||||
|
||||
/**
|
||||
* Inner properties, in immutable format.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public class ImmutableInnerClassProperties {
|
||||
|
||||
private final Foo first;
|
||||
|
||||
private Foo second;
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private final SimplePojo third;
|
||||
|
||||
private final Fourth fourth;
|
||||
|
||||
public ImmutableInnerClassProperties(Foo first, Foo second, SimplePojo third,
|
||||
Fourth fourth) {
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
this.third = third;
|
||||
this.fourth = fourth;
|
||||
}
|
||||
|
||||
public Foo getFirst() {
|
||||
return this.first;
|
||||
}
|
||||
|
||||
public Foo getTheSecond() {
|
||||
return this.second;
|
||||
}
|
||||
|
||||
public void setTheSecond(Foo second) {
|
||||
this.second = second;
|
||||
}
|
||||
|
||||
public SimplePojo getThird() {
|
||||
return this.third;
|
||||
}
|
||||
|
||||
public Fourth getFourth() {
|
||||
return this.fourth;
|
||||
}
|
||||
|
||||
public static class Foo {
|
||||
|
||||
private String name;
|
||||
|
||||
private final Bar bar = new Bar();
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Bar getBar() {
|
||||
return this.bar;
|
||||
}
|
||||
|
||||
public static class Bar {
|
||||
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public enum Fourth {
|
||||
|
||||
YES, NO
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.configurationsample.immutable;
|
||||
|
||||
/**
|
||||
* Simple immutable properties with primitive types.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class ImmutablePrimitiveProperties {
|
||||
|
||||
private final boolean flag;
|
||||
|
||||
private final byte octet;
|
||||
|
||||
private final char letter;
|
||||
|
||||
private final short number;
|
||||
|
||||
private final int counter;
|
||||
|
||||
private final long value;
|
||||
|
||||
private final float percentage;
|
||||
|
||||
private final double ratio;
|
||||
|
||||
public ImmutablePrimitiveProperties(boolean flag, byte octet, char letter,
|
||||
short number, int counter, long value, float percentage, double ratio) {
|
||||
this.flag = flag;
|
||||
this.octet = octet;
|
||||
this.letter = letter;
|
||||
this.number = number;
|
||||
this.counter = counter;
|
||||
this.value = value;
|
||||
this.percentage = percentage;
|
||||
this.ratio = ratio;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.configurationsample.immutable;
|
||||
|
||||
import org.springframework.boot.configurationsample.DefaultValue;
|
||||
|
||||
/**
|
||||
* Simple immutable properties with primitive types and defaults.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class ImmutablePrimitiveWithDefaultsProperties {
|
||||
|
||||
private final boolean flag;
|
||||
|
||||
private final byte octet;
|
||||
|
||||
private final char letter;
|
||||
|
||||
private final short number;
|
||||
|
||||
private final int counter;
|
||||
|
||||
private final long value;
|
||||
|
||||
private final float percentage;
|
||||
|
||||
private final double ratio;
|
||||
|
||||
public ImmutablePrimitiveWithDefaultsProperties(@DefaultValue("true") boolean flag,
|
||||
@DefaultValue("120") byte octet, @DefaultValue("a") char letter,
|
||||
@DefaultValue("1000") short number, @DefaultValue("42") int counter,
|
||||
@DefaultValue("2000") long value, @DefaultValue("0.5") float percentage,
|
||||
@DefaultValue("42.42") double ratio) {
|
||||
this.flag = flag;
|
||||
this.octet = octet;
|
||||
this.letter = letter;
|
||||
this.number = number;
|
||||
this.counter = counter;
|
||||
this.value = value;
|
||||
this.percentage = percentage;
|
||||
this.ratio = ratio;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.configurationsample.immutable;
|
||||
|
||||
import org.springframework.boot.configurationsample.DefaultValue;
|
||||
|
||||
/**
|
||||
* Simple immutable properties with primitive wrapper types and defaults.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class ImmutablePrimitiveWrapperWithDefaultsProperties {
|
||||
|
||||
private final Boolean flag;
|
||||
|
||||
private final Byte octet;
|
||||
|
||||
private final Character letter;
|
||||
|
||||
private final Short number;
|
||||
|
||||
private final Integer counter;
|
||||
|
||||
private final Long value;
|
||||
|
||||
private final Float percentage;
|
||||
|
||||
private final Double ratio;
|
||||
|
||||
public ImmutablePrimitiveWrapperWithDefaultsProperties(
|
||||
@DefaultValue("true") Boolean flag, @DefaultValue("120") Byte octet,
|
||||
@DefaultValue("a") Character letter, @DefaultValue("1000") Short number,
|
||||
@DefaultValue("42") Integer counter, @DefaultValue("2000") Long value,
|
||||
@DefaultValue("0.5") Float percentage, @DefaultValue("42.42") Double ratio) {
|
||||
this.flag = flag;
|
||||
this.octet = octet;
|
||||
this.letter = letter;
|
||||
this.number = number;
|
||||
this.counter = counter;
|
||||
this.value = value;
|
||||
this.percentage = percentage;
|
||||
this.ratio = ratio;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.configurationsample.immutable;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
import org.springframework.boot.configurationsample.ConfigurationProperties;
|
||||
import org.springframework.boot.configurationsample.DefaultValue;
|
||||
|
||||
/**
|
||||
* Simple properties, in immutable format.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@ConfigurationProperties("immutable")
|
||||
public class ImmutableSimpleProperties {
|
||||
|
||||
/**
|
||||
* The name of this simple properties.
|
||||
*/
|
||||
private final String theName;
|
||||
|
||||
/**
|
||||
* A simple flag.
|
||||
*/
|
||||
private final boolean flag;
|
||||
|
||||
// An interface can still be injected because it might have a converter
|
||||
private final Comparator<?> comparator;
|
||||
|
||||
// Even if it is not exposed, we're still offering a way to bind the value via the
|
||||
// constructor so it should be present in the metadata
|
||||
@SuppressWarnings("unused")
|
||||
private final Long counter;
|
||||
|
||||
public ImmutableSimpleProperties(@DefaultValue("boot") String theName, boolean flag,
|
||||
Comparator<?> comparator, Long counter) {
|
||||
this.theName = theName;
|
||||
this.flag = flag;
|
||||
this.comparator = comparator;
|
||||
this.counter = counter;
|
||||
}
|
||||
|
||||
public String getTheName() {
|
||||
return this.theName;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public boolean isFlag() {
|
||||
return this.flag;
|
||||
}
|
||||
|
||||
public Comparator<?> getComparator() {
|
||||
return this.comparator;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.configurationsample.specific;
|
||||
|
||||
import org.springframework.boot.configurationsample.ConfigurationProperties;
|
||||
import org.springframework.boot.configurationsample.DefaultValue;
|
||||
|
||||
/**
|
||||
* Demonstrates that an invalid default character value leads to a compilation failure.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@ConfigurationProperties("test")
|
||||
public class InvalidDefaultValueCharacterProperties {
|
||||
|
||||
private final char letter;
|
||||
|
||||
public InvalidDefaultValueCharacterProperties(@DefaultValue("bad") char letter) {
|
||||
this.letter = letter;
|
||||
}
|
||||
|
||||
public char getLetter() {
|
||||
return this.letter;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.configurationsample.specific;
|
||||
|
||||
import org.springframework.boot.configurationsample.ConfigurationProperties;
|
||||
import org.springframework.boot.configurationsample.DefaultValue;
|
||||
|
||||
/**
|
||||
* Demonstrates that an invalid default floating point value leads to a compilation
|
||||
* failure.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@ConfigurationProperties("test")
|
||||
public class InvalidDefaultValueFloatingPointProperties {
|
||||
|
||||
private final Double ratio;
|
||||
|
||||
public InvalidDefaultValueFloatingPointProperties(
|
||||
@DefaultValue("55.55.33") Double ratio) {
|
||||
this.ratio = ratio;
|
||||
}
|
||||
|
||||
public Double getRatio() {
|
||||
return this.ratio;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.configurationsample.specific;
|
||||
|
||||
import org.springframework.boot.configurationsample.ConfigurationProperties;
|
||||
import org.springframework.boot.configurationsample.DefaultValue;
|
||||
|
||||
/**
|
||||
* Demonstrates that an invalid default number value leads to a compilation failure.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@ConfigurationProperties("test")
|
||||
public class InvalidDefaultValueNumberProperties {
|
||||
|
||||
private final int counter;
|
||||
|
||||
public InvalidDefaultValueNumberProperties(@DefaultValue("invalid") int counter) {
|
||||
this.counter = counter;
|
||||
}
|
||||
|
||||
public int getCounter() {
|
||||
return this.counter;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.configurationsample.specific;
|
||||
|
||||
/**
|
||||
* A type with more than one constructor.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public class TwoConstructorsExample {
|
||||
|
||||
private String name;
|
||||
|
||||
public TwoConstructorsExample() {
|
||||
}
|
||||
|
||||
public TwoConstructorsExample(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user