Merge branch '2.7.x'

Closes gh-33871
This commit is contained in:
Moritz Halbritter
2023-01-18 12:08:58 +01:00
4 changed files with 97 additions and 19 deletions

View File

@@ -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 {
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();
}

View File

@@ -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 {
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 {
}
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 {
}
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() {