From 8cbd7f5cd01b69dda898dc637e67a8c63d2b937a Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 21 Apr 2020 15:59:34 +0200 Subject: [PATCH] Polish "Add support for initializing nested object when nothing bound" This commit harmonizes the change made to @DefaultValue to the annotation processor. If such annotation is added to a scalar value with no value at all, no default value is produced. Closes gh-18917 --- ...ationMetadataAnnotationProcessorTests.java | 11 +++++ ...ablePropertiesMetadataGenerationTests.java | 10 ++++- .../configurationsample/DefaultValue.java | 2 +- .../DeducedImmutableClassProperties.java | 3 +- .../specific/EmptyDefaultValueProperties.java | 42 +++++++++++++++++++ 5 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/specific/EmptyDefaultValueProperties.java diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessorTests.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessorTests.java index c1fee73ad3a..042128f410a 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessorTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessorTests.java @@ -19,6 +19,7 @@ package org.springframework.boot.configurationprocessor; import org.junit.jupiter.api.Test; import org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata; +import org.springframework.boot.configurationprocessor.metadata.ItemMetadata; import org.springframework.boot.configurationprocessor.metadata.Metadata; import org.springframework.boot.configurationsample.recursive.RecursiveProperties; import org.springframework.boot.configurationsample.simple.ClassWithNestedProperties; @@ -39,6 +40,7 @@ import org.springframework.boot.configurationsample.specific.BoxingPojo; import org.springframework.boot.configurationsample.specific.BuilderPojo; import org.springframework.boot.configurationsample.specific.DeprecatedUnrelatedMethodPojo; import org.springframework.boot.configurationsample.specific.DoubleRegistrationProperties; +import org.springframework.boot.configurationsample.specific.EmptyDefaultValueProperties; import org.springframework.boot.configurationsample.specific.ExcludedTypesPojo; import org.springframework.boot.configurationsample.specific.InnerClassAnnotatedGetterConfig; import org.springframework.boot.configurationsample.specific.InnerClassHierarchicalProperties; @@ -362,6 +364,15 @@ class ConfigurationMetadataAnnotationProcessorTests extends AbstractMetadataGene .withMessageContaining("Compilation failed"); } + @Test + void constructorParameterPropertyWithEmptyDefaultValueOnProperty() { + ConfigurationMetadata metadata = compile(EmptyDefaultValueProperties.class); + assertThat(metadata).has(Metadata.withProperty("test.name")); + ItemMetadata nameMetadata = metadata.getItems().stream().filter((item) -> item.getName().equals("test.name")) + .findFirst().get(); + assertThat(nameMetadata.getDefaultValue()).isNull(); + } + @Test void recursivePropertiesDoNotCauseAStackOverflow() { compile(RecursiveProperties.class); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/DeducedImmutablePropertiesMetadataGenerationTests.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/DeducedImmutablePropertiesMetadataGenerationTests.java index 84bc1f22ae1..c504e314857 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/DeducedImmutablePropertiesMetadataGenerationTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/DeducedImmutablePropertiesMetadataGenerationTests.java @@ -19,6 +19,7 @@ package org.springframework.boot.configurationprocessor; import org.junit.jupiter.api.Test; import org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata; +import org.springframework.boot.configurationprocessor.metadata.ItemMetadata; import org.springframework.boot.configurationprocessor.metadata.Metadata; import org.springframework.boot.configurationsample.immutable.DeducedImmutableClassProperties; @@ -28,6 +29,7 @@ import static org.assertj.core.api.Assertions.assertThat; * Metadata generation tests for immutable properties deduced because they're nested. * * @author Phillip Webb + * @author Stephane Nicoll */ class DeducedImmutablePropertiesMetadataGenerationTests extends AbstractMetadataGenerationTests { @@ -35,7 +37,13 @@ class DeducedImmutablePropertiesMetadataGenerationTests extends AbstractMetadata void immutableSimpleProperties() { ConfigurationMetadata metadata = compile(DeducedImmutableClassProperties.class); assertThat(metadata).has(Metadata.withGroup("test").fromSource(DeducedImmutableClassProperties.class)); - assertThat(metadata).has(Metadata.withProperty("test.nested.name", String.class)); + assertThat(metadata).has(Metadata.withGroup("test.nested", DeducedImmutableClassProperties.Nested.class) + .fromSource(DeducedImmutableClassProperties.class)); + assertThat(metadata).has(Metadata.withProperty("test.nested.name", String.class) + .fromSource(DeducedImmutableClassProperties.Nested.class)); + ItemMetadata nestedMetadata = metadata.getItems().stream() + .filter((item) -> item.getName().equals("test.nested")).findFirst().get(); + assertThat(nestedMetadata.getDefaultValue()).isNull(); } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/DefaultValue.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/DefaultValue.java index 32604a46210..0c3751e9728 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/DefaultValue.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/DefaultValue.java @@ -33,6 +33,6 @@ import java.lang.annotation.Target; @Documented public @interface DefaultValue { - String[] value(); + String[] value() default {}; } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/immutable/DeducedImmutableClassProperties.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/immutable/DeducedImmutableClassProperties.java index 5a5d799cd78..7b3d26f85d3 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/immutable/DeducedImmutableClassProperties.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/immutable/DeducedImmutableClassProperties.java @@ -18,6 +18,7 @@ package org.springframework.boot.configurationsample.immutable; import org.springframework.boot.configurationsample.ConfigurationProperties; import org.springframework.boot.configurationsample.ConstructorBinding; +import org.springframework.boot.configurationsample.DefaultValue; /** * Inner properties, in immutable format. @@ -30,7 +31,7 @@ public class DeducedImmutableClassProperties { private final Nested nested; - public DeducedImmutableClassProperties(Nested nested) { + public DeducedImmutableClassProperties(@DefaultValue Nested nested) { this.nested = nested; } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/specific/EmptyDefaultValueProperties.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/specific/EmptyDefaultValueProperties.java new file mode 100644 index 00000000000..fc55bd95096 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/specific/EmptyDefaultValueProperties.java @@ -0,0 +1,42 @@ +/* + * 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.specific; + +import org.springframework.boot.configurationsample.ConfigurationProperties; +import org.springframework.boot.configurationsample.ConstructorBinding; +import org.springframework.boot.configurationsample.DefaultValue; + +/** + * Demonstrates that an empty default value on a property leads to no default value. + * + * @author Stephane Nicoll + */ +@ConfigurationProperties("test") +public class EmptyDefaultValueProperties { + + private final String name; + + @ConstructorBinding + public EmptyDefaultValueProperties(@DefaultValue String name) { + this.name = name; + } + + public String getName() { + return this.name; + } + +}