Browse Source

Consistently detect the default value of a property

This is a follow-up of gh-46599 where detecting the default value
suffer from the same problem. Rather than using a name, the resolver now
provides the field itself. This also adds a dedicated test for the use
of @Name with Lombok.

Closes gh-46662
pull/46752/head
Stéphane Nicoll 5 months ago
parent
commit
b190e8077b
  1. 2
      spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/JavaBeanPropertyDescriptor.java
  2. 2
      spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/LombokPropertyDescriptor.java
  3. 9
      spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/MetadataGenerationEnvironment.java
  4. 51
      spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/NameAnnotationPropertiesTests.java
  5. 21
      spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/PropertyDescriptorResolverTests.java
  6. 22
      spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/name/ConstructorParameterNameAnnotationProperties.java
  7. 20
      spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/name/JavaBeanNameAnnotationProperties.java
  8. 47
      spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/name/LombokNameAnnotationProperties.java
  9. 12
      spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/name/RecordComponentNameAnnotationProperties.java

2
spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/JavaBeanPropertyDescriptor.java

@ -64,7 +64,7 @@ class JavaBeanPropertyDescriptor extends PropertyDescriptor { @@ -64,7 +64,7 @@ class JavaBeanPropertyDescriptor extends PropertyDescriptor {
@Override
protected Object resolveDefaultValue(MetadataGenerationEnvironment environment) {
return environment.getFieldDefaultValue(getDeclaringElement(), getName());
return environment.getFieldDefaultValue(getDeclaringElement(), this.field);
}
@Override

2
spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/LombokPropertyDescriptor.java

@ -76,7 +76,7 @@ class LombokPropertyDescriptor extends PropertyDescriptor { @@ -76,7 +76,7 @@ class LombokPropertyDescriptor extends PropertyDescriptor {
@Override
protected Object resolveDefaultValue(MetadataGenerationEnvironment environment) {
return environment.getFieldDefaultValue(getDeclaringElement(), getName());
return environment.getFieldDefaultValue(getDeclaringElement(), this.field);
}
@Override

9
spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/MetadataGenerationEnvironment.java

@ -132,14 +132,15 @@ class MetadataGenerationEnvironment { @@ -132,14 +132,15 @@ class MetadataGenerationEnvironment {
}
/**
* Return the default value of the field with the specified {@code name}.
* Return the default value of the given {@code field}.
* @param type the type to consider
* @param name the name of the field
* @param field the field or {@code null} if it is not available
* @return the default value or {@code null} if the field does not exist or no default
* value has been detected
*/
Object getFieldDefaultValue(TypeElement type, String name) {
return this.defaultValues.computeIfAbsent(type, this::resolveFieldValues).get(name);
Object getFieldDefaultValue(TypeElement type, VariableElement field) {
return (field != null) ? this.defaultValues.computeIfAbsent(type, this::resolveFieldValues)
.get(field.getSimpleName().toString()) : null;
}
boolean isExcluded(TypeMirror type) {

51
spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/NameAnnotationPropertiesTests.java

@ -20,9 +20,10 @@ import org.junit.jupiter.api.Test; @@ -20,9 +20,10 @@ 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.immutable.ConstructorParameterNameAnnotationProperties;
import org.springframework.boot.configurationsample.immutable.JavaBeanNameAnnotationProperties;
import org.springframework.boot.configurationsample.immutable.RecordComponentNameAnnotationProperties;
import org.springframework.boot.configurationsample.name.ConstructorParameterNameAnnotationProperties;
import org.springframework.boot.configurationsample.name.JavaBeanNameAnnotationProperties;
import org.springframework.boot.configurationsample.name.LombokNameAnnotationProperties;
import org.springframework.boot.configurationsample.name.RecordComponentNameAnnotationProperties;
import static org.assertj.core.api.Assertions.assertThat;
@ -30,28 +31,60 @@ import static org.assertj.core.api.Assertions.assertThat; @@ -30,28 +31,60 @@ import static org.assertj.core.api.Assertions.assertThat;
* Metadata generation tests for using {@code @Name}.
*
* @author Phillip Webb
* @author Stephane Nicoll
*/
class NameAnnotationPropertiesTests extends AbstractMetadataGenerationTests {
@Test
void constructorParameterNameAnnotationProperties() {
ConfigurationMetadata metadata = compile(ConstructorParameterNameAnnotationProperties.class);
assertThat(metadata).has(Metadata.withProperty("named.import", String.class)
.fromSource(ConstructorParameterNameAnnotationProperties.class));
assertThat(metadata)
.has(Metadata.withProperty("named.import", String.class)
.fromSource(ConstructorParameterNameAnnotationProperties.class)
.withDescription("Imports to apply."))
.has(Metadata.withProperty("named.default", Boolean.class)
.fromSource(ConstructorParameterNameAnnotationProperties.class)
.withDefaultValue("Whether default mode is enabled.")
.withDefaultValue(true));
}
@Test
void recordComponentNameAnnotationProperties() {
ConfigurationMetadata metadata = compile(RecordComponentNameAnnotationProperties.class);
assertThat(metadata).has(Metadata.withProperty("named.import", String.class)
.fromSource(RecordComponentNameAnnotationProperties.class));
assertThat(metadata)
.has(Metadata.withProperty("named.import", String.class)
.fromSource(RecordComponentNameAnnotationProperties.class)
.withDescription("Imports to apply."))
.has(Metadata.withProperty("named.default", Boolean.class)
.fromSource(RecordComponentNameAnnotationProperties.class)
.withDefaultValue("Whether default mode is enabled.")
.withDefaultValue(true));
}
@Test
void javaBeanNameAnnotationProperties() {
ConfigurationMetadata metadata = compile(JavaBeanNameAnnotationProperties.class);
assertThat(metadata).has(
Metadata.withProperty("named.import", String.class).fromSource(JavaBeanNameAnnotationProperties.class));
assertThat(metadata)
.has(Metadata.withProperty("named.import", String.class)
.fromSource(JavaBeanNameAnnotationProperties.class)
.withDescription("Imports to apply."))
.has(Metadata.withProperty("named.default", Boolean.class)
.fromSource(JavaBeanNameAnnotationProperties.class)
.withDefaultValue("Whether default mode is enabled.")
.withDefaultValue(true));
}
@Test
void lombokNameAnnotationProperties() {
ConfigurationMetadata metadata = compile(LombokNameAnnotationProperties.class);
assertThat(metadata)
.has(Metadata.withProperty("named.import", String.class)
.fromSource(LombokNameAnnotationProperties.class)
.withDescription("Imports to apply."))
.has(Metadata.withProperty("named.default", Boolean.class)
.fromSource(LombokNameAnnotationProperties.class)
.withDefaultValue("Whether default mode is enabled.")
.withDefaultValue(true));
}
}

21
spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/PropertyDescriptorResolverTests.java

@ -31,17 +31,18 @@ import org.junit.jupiter.api.Test; @@ -31,17 +31,18 @@ import org.junit.jupiter.api.Test;
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.ConstructorParameterNameAnnotationProperties;
import org.springframework.boot.configurationsample.immutable.ImmutableClassConstructorBindingProperties;
import org.springframework.boot.configurationsample.immutable.ImmutableDeducedConstructorBindingProperties;
import org.springframework.boot.configurationsample.immutable.ImmutableMultiConstructorProperties;
import org.springframework.boot.configurationsample.immutable.ImmutableSimpleProperties;
import org.springframework.boot.configurationsample.immutable.JavaBeanNameAnnotationProperties;
import org.springframework.boot.configurationsample.immutable.RecordComponentNameAnnotationProperties;
import org.springframework.boot.configurationsample.lombok.LombokExplicitProperties;
import org.springframework.boot.configurationsample.lombok.LombokSimpleDataProperties;
import org.springframework.boot.configurationsample.lombok.LombokSimpleProperties;
import org.springframework.boot.configurationsample.lombok.LombokSimpleValueProperties;
import org.springframework.boot.configurationsample.name.ConstructorParameterNameAnnotationProperties;
import org.springframework.boot.configurationsample.name.JavaBeanNameAnnotationProperties;
import org.springframework.boot.configurationsample.name.LombokNameAnnotationProperties;
import org.springframework.boot.configurationsample.name.RecordComponentNameAnnotationProperties;
import org.springframework.boot.configurationsample.simple.AutowiredProperties;
import org.springframework.boot.configurationsample.simple.HierarchicalProperties;
import org.springframework.boot.configurationsample.simple.HierarchicalPropertiesGrandparent;
@ -162,21 +163,27 @@ class PropertyDescriptorResolverTests { @@ -162,21 +163,27 @@ class PropertyDescriptorResolverTests {
}
@Test
void contructorParameterPropertyWithNameAnnotationParameter() {
void constructorParameterPropertyWithNameAnnotationParameter() {
process(ConstructorParameterNameAnnotationProperties.class,
propertyNames((stream) -> assertThat(stream).containsExactly("import")));
propertyNames((stream) -> assertThat(stream).containsOnly("import", "default")));
}
@Test
void recordComponentPropertyWithNameAnnotationParameter() {
process(RecordComponentNameAnnotationProperties.class,
propertyNames((stream) -> assertThat(stream).containsExactly("import")));
propertyNames((stream) -> assertThat(stream).containsOnly("import", "default")));
}
@Test
void javaBeanPropertyWithNameAnnotationParameter() {
process(JavaBeanNameAnnotationProperties.class,
propertyNames((stream) -> assertThat(stream).containsExactly("import")));
propertyNames((stream) -> assertThat(stream).containsOnly("import", "default")));
}
@Test
void lombokPropertyWithNameAnnotationParameter() {
process(LombokNameAnnotationProperties.class,
propertyNames((stream) -> assertThat(stream).containsOnly("import", "default")));
}
private BiConsumer<TypeElement, MetadataGenerationEnvironment> properties(

22
spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/immutable/ConstructorParameterNameAnnotationProperties.java → spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/name/ConstructorParameterNameAnnotationProperties.java

@ -14,27 +14,43 @@ @@ -14,27 +14,43 @@
* limitations under the License.
*/
package org.springframework.boot.configurationsample.immutable;
package org.springframework.boot.configurationsample.name;
import org.springframework.boot.configurationsample.ConfigurationProperties;
import org.springframework.boot.configurationsample.DefaultValue;
import org.springframework.boot.configurationsample.Name;
/**
* Immutable class properties making use of {@code @Name}.
* Constructor properties making use of {@code @Name}.
*
* @author Phillip Webb
* @author Stephane Nicoll
*/
@ConfigurationProperties("named")
public class ConstructorParameterNameAnnotationProperties {
/**
* Imports to apply.
*/
private final String imports;
public ConstructorParameterNameAnnotationProperties(@Name("import") String imports) {
/**
* Whether default mode is enabled.
*/
private final boolean defaultValue;
public ConstructorParameterNameAnnotationProperties(@Name("import") String imports,
@Name("default") @DefaultValue("true") boolean defaultValue) {
this.imports = imports;
this.defaultValue = defaultValue;
}
public String getImports() {
return this.imports;
}
public boolean isDefaultValue() {
return this.defaultValue;
}
}

20
spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/immutable/JavaBeanNameAnnotationProperties.java → spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/name/JavaBeanNameAnnotationProperties.java

@ -14,7 +14,7 @@ @@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.configurationsample.immutable;
package org.springframework.boot.configurationsample.name;
import org.springframework.boot.configurationsample.ConfigurationProperties;
import org.springframework.boot.configurationsample.Name;
@ -23,13 +23,23 @@ import org.springframework.boot.configurationsample.Name; @@ -23,13 +23,23 @@ import org.springframework.boot.configurationsample.Name;
* Java bean properties making use of {@code @Name}.
*
* @author Andy Wilkinson
* @author Stephane Nicoll
*/
@ConfigurationProperties("named")
public class JavaBeanNameAnnotationProperties {
/**
* Imports to apply.
*/
@Name("import")
private String imports;
/**
* Whether default mode is enabled.
*/
@Name("default")
private boolean defaultValue = true;
public String getImports() {
return this.imports;
}
@ -38,4 +48,12 @@ public class JavaBeanNameAnnotationProperties { @@ -38,4 +48,12 @@ public class JavaBeanNameAnnotationProperties {
this.imports = imports;
}
public boolean isDefaultValue() {
return this.defaultValue;
}
public void setDefaultValue(boolean defaultValue) {
this.defaultValue = defaultValue;
}
}

47
spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/name/LombokNameAnnotationProperties.java

@ -0,0 +1,47 @@ @@ -0,0 +1,47 @@
/*
* Copyright 2012-present 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.name;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.configurationsample.ConfigurationProperties;
import org.springframework.boot.configurationsample.Name;
/**
* Lombok properties making use of {@code @Name}.
*
* @author Stephane Nicoll
*/
@Getter
@Setter
@ConfigurationProperties("named")
public class LombokNameAnnotationProperties {
/**
* Imports to apply.
*/
@Name("import")
private String imports;
/**
* Whether default mode is enabled.
*/
@Name("default")
private boolean defaultValue = true;
}

12
spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/immutable/RecordComponentNameAnnotationProperties.java → spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/name/RecordComponentNameAnnotationProperties.java

@ -14,18 +14,22 @@ @@ -14,18 +14,22 @@
* limitations under the License.
*/
package org.springframework.boot.configurationsample.immutable;
package org.springframework.boot.configurationsample.name;
import org.springframework.boot.configurationsample.ConfigurationProperties;
import org.springframework.boot.configurationsample.DefaultValue;
import org.springframework.boot.configurationsample.Name;
/**
* Immutable record properties making use of {@code @Name}.
* Record properties making use of {@code @Name}.
*
* @param imports some imports
* @param imports Imports to apply.
* @param defaultValue Whether default mode is enabled.
* @author Andy Wilkinson
* @author Stephane Nicoll
*/
@ConfigurationProperties("named")
public record RecordComponentNameAnnotationProperties(@Name("import") String imports) {
public record RecordComponentNameAnnotationProperties(@Name("import") String imports,
@Name("default") @DefaultValue("true") boolean defaultValue) {
}
Loading…
Cancel
Save