Browse Source

Merge branch '2.7.x'

Closes gh-33871
pull/33886/head
Moritz Halbritter 3 years ago
parent
commit
ae64b205d4
  1. 17
      spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/PropertyDescriptorResolver.java
  2. 50
      spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/TypeElementMembers.java
  3. 11
      spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessorTests.java
  4. 38
      spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/simple/DeprecatedRecord.java

17
spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/PropertyDescriptorResolver.java

@ -59,23 +59,22 @@ class PropertyDescriptorResolver { @@ -59,23 +59,22 @@ class PropertyDescriptorResolver {
if (factoryMethod != null) {
return resolveJavaBeanProperties(type, factoryMethod, members);
}
return resolve(ConfigurationPropertiesTypeElement.of(type, this.environment), factoryMethod, members);
return resolve(ConfigurationPropertiesTypeElement.of(type, this.environment), members);
}
private Stream<PropertyDescriptor<?>> resolve(ConfigurationPropertiesTypeElement type,
ExecutableElement factoryMethod, TypeElementMembers members) {
private Stream<PropertyDescriptor<?>> resolve(ConfigurationPropertiesTypeElement type, TypeElementMembers members) {
if (type.isConstructorBindingEnabled()) {
ExecutableElement constructor = type.getBindConstructor();
if (constructor != null) {
return resolveConstructorProperties(type.getType(), factoryMethod, members, constructor);
return resolveConstructorProperties(type.getType(), members, constructor);
}
return Stream.empty();
}
return resolveJavaBeanProperties(type.getType(), factoryMethod, members);
return resolveJavaBeanProperties(type.getType(), null, members);
}
Stream<PropertyDescriptor<?>> resolveConstructorProperties(TypeElement type, ExecutableElement factoryMethod,
TypeElementMembers members, ExecutableElement constructor) {
Stream<PropertyDescriptor<?>> resolveConstructorProperties(TypeElement type, TypeElementMembers members,
ExecutableElement constructor) {
Map<String, PropertyDescriptor<?>> candidates = new LinkedHashMap<>();
constructor.getParameters().forEach((parameter) -> {
String name = getParameterName(parameter);
@ -83,8 +82,8 @@ class PropertyDescriptorResolver { @@ -83,8 +82,8 @@ class PropertyDescriptorResolver {
ExecutableElement getter = members.getPublicGetter(name, propertyType);
ExecutableElement setter = members.getPublicSetter(name, propertyType);
VariableElement field = members.getFields().get(name);
register(candidates, new ConstructorParameterPropertyDescriptor(type, factoryMethod, parameter, name,
propertyType, field, getter, setter));
register(candidates, new ConstructorParameterPropertyDescriptor(type, null, parameter, name, propertyType,
field, getter, setter));
});
return candidates.values().stream();
}

50
spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/TypeElementMembers.java

@ -38,15 +38,20 @@ import javax.lang.model.util.ElementFilter; @@ -38,15 +38,20 @@ import javax.lang.model.util.ElementFilter;
*
* @author Stephane Nicoll
* @author Phillip Webb
* @author Moritz Halbritter
*/
class TypeElementMembers {
private static final String OBJECT_CLASS_NAME = Object.class.getName();
private static final String RECORD_CLASS_NAME = "java.lang.Record";
private final MetadataGenerationEnvironment env;
private final TypeElement targetType;
private final boolean isRecord;
private final Map<String, VariableElement> fields = new LinkedHashMap<>();
private final Map<String, List<ExecutableElement>> publicGetters = new LinkedHashMap<>();
@ -56,18 +61,20 @@ class TypeElementMembers { @@ -56,18 +61,20 @@ class TypeElementMembers {
TypeElementMembers(MetadataGenerationEnvironment env, TypeElement targetType) {
this.env = env;
this.targetType = targetType;
this.isRecord = RECORD_CLASS_NAME.equals(targetType.getSuperclass().toString());
process(targetType);
}
private void process(TypeElement element) {
for (ExecutableElement method : ElementFilter.methodsIn(element.getEnclosedElements())) {
processMethod(method);
}
for (VariableElement field : ElementFilter.fieldsIn(element.getEnclosedElements())) {
processField(field);
}
for (ExecutableElement method : ElementFilter.methodsIn(element.getEnclosedElements())) {
processMethod(method);
}
Element superType = this.env.getTypeUtils().asElement(element.getSuperclass());
if (superType instanceof TypeElement && !OBJECT_CLASS_NAME.equals(superType.toString())) {
if (superType instanceof TypeElement && !OBJECT_CLASS_NAME.equals(superType.toString())
&& !RECORD_CLASS_NAME.equals(superType.toString())) {
process((TypeElement) superType);
}
}
@ -122,12 +129,22 @@ class TypeElementMembers { @@ -122,12 +129,22 @@ class TypeElementMembers {
}
private boolean isGetter(ExecutableElement method) {
boolean hasParameters = !method.getParameters().isEmpty();
boolean returnsVoid = TypeKind.VOID == method.getReturnType().getKind();
if (hasParameters || returnsVoid) {
return false;
}
String name = method.getSimpleName().toString();
return ((name.startsWith("get") && name.length() > 3) || (name.startsWith("is") && name.length() > 2))
&& method.getParameters().isEmpty() && (TypeKind.VOID != method.getReturnType().getKind());
if (this.isRecord && this.fields.containsKey(name)) {
return true;
}
return (name.startsWith("get") && name.length() > 3) || (name.startsWith("is") && name.length() > 2);
}
private boolean isSetter(ExecutableElement method) {
if (this.isRecord) {
return false;
}
final String name = method.getSimpleName().toString();
return (name.startsWith("set") && name.length() > 3 && method.getParameters().size() == 1
&& isSetterReturnType(method));
@ -151,16 +168,29 @@ class TypeElementMembers { @@ -151,16 +168,29 @@ class TypeElementMembers {
}
private String getAccessorName(String methodName) {
String name = methodName.startsWith("is") ? methodName.substring(2) : methodName.substring(3);
if (this.isRecord) {
return methodName;
}
String name;
if (methodName.startsWith("is")) {
name = methodName.substring(2);
}
else if (methodName.startsWith("get")) {
name = methodName.substring(3);
}
else if (methodName.startsWith("set")) {
name = methodName.substring(3);
}
else {
throw new AssertionError("methodName must start with 'is', 'get' or 'set', was '" + methodName + "'");
}
name = Character.toLowerCase(name.charAt(0)) + name.substring(1);
return name;
}
private void processField(VariableElement field) {
String name = field.getSimpleName().toString();
if (!this.fields.containsKey(name)) {
this.fields.put(name, field);
}
this.fields.putIfAbsent(name, field);
}
Map<String, VariableElement> getFields() {

11
spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessorTests.java

@ -24,6 +24,7 @@ import org.springframework.boot.configurationprocessor.metadata.Metadata; @@ -24,6 +24,7 @@ import org.springframework.boot.configurationprocessor.metadata.Metadata;
import org.springframework.boot.configurationsample.recursive.RecursiveProperties;
import org.springframework.boot.configurationsample.simple.ClassWithNestedProperties;
import org.springframework.boot.configurationsample.simple.DeprecatedFieldSingleProperty;
import org.springframework.boot.configurationsample.simple.DeprecatedRecord;
import org.springframework.boot.configurationsample.simple.DeprecatedSingleProperty;
import org.springframework.boot.configurationsample.simple.DescriptionProperties;
import org.springframework.boot.configurationsample.simple.HierarchicalProperties;
@ -219,6 +220,16 @@ class ConfigurationMetadataAnnotationProcessorTests extends AbstractMetadataGene @@ -219,6 +220,16 @@ class ConfigurationMetadataAnnotationProcessorTests extends AbstractMetadataGene
.withNoDeprecation().fromSource(type));
}
@Test
void deprecatedPropertyOnRecord() {
Class<?> type = DeprecatedRecord.class;
ConfigurationMetadata metadata = compile(type);
assertThat(metadata).has(Metadata.withGroup("deprecated-record").fromSource(type));
assertThat(metadata).has(Metadata.withProperty("deprecated-record.alpha", String.class).fromSource(type)
.withDeprecation("some-reason", null));
assertThat(metadata).has(Metadata.withProperty("deprecated-record.bravo", String.class).fromSource(type));
}
@Test
void typBoxing() {
Class<?> type = BoxingPojo.class;

38
spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/simple/DeprecatedRecord.java

@ -0,0 +1,38 @@ @@ -0,0 +1,38 @@
/*
* Copyright 2012-2023 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.simple;
import org.springframework.boot.configurationsample.ConfigurationProperties;
import org.springframework.boot.configurationsample.DeprecatedConfigurationProperty;
/**
* Configuration properties as record with deprecated property.
* @param alpha alpha property, deprecated
* @param bravo bravo property
*
* @author Moritz Halbritter
*/
@ConfigurationProperties("deprecated-record")
public record DeprecatedRecord(String alpha, String bravo) {
@Deprecated
@DeprecatedConfigurationProperty(reason = "some-reason")
public String alpha() {
return this.alpha;
}
}
Loading…
Cancel
Save