Suppress deprecated warnings for autowiring

This commit extends our handling of deprecated with AOT to autowiring.

Closes gh-33295
This commit is contained in:
Stéphane Nicoll
2024-07-31 16:48:18 +02:00
parent 321e8a58ae
commit 850a0de1b0
5 changed files with 261 additions and 38 deletions

View File

@@ -63,6 +63,7 @@ import org.springframework.beans.factory.aot.AutowiredMethodArgumentsResolver;
import org.springframework.beans.factory.aot.BeanRegistrationAotContribution;
import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
import org.springframework.beans.factory.aot.BeanRegistrationCode;
import org.springframework.beans.factory.aot.CodeWarnings;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor;
@@ -984,8 +985,11 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
method.addParameter(RegisteredBean.class, REGISTERED_BEAN_PARAMETER);
method.addParameter(this.target, INSTANCE_PARAMETER);
method.returns(this.target);
method.addCode(generateMethodCode(generatedClass.getName(),
generationContext.getRuntimeHints()));
CodeWarnings codeWarnings = new CodeWarnings();
codeWarnings.detectDeprecation(this.target);
method.addCode(generateMethodCode(codeWarnings,
generatedClass.getName(), generationContext.getRuntimeHints()));
codeWarnings.suppress(method);
});
beanRegistrationCode.addInstancePostProcessor(generateMethod.toMethodReference());
@@ -994,35 +998,37 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
}
}
private CodeBlock generateMethodCode(ClassName targetClassName, RuntimeHints hints) {
private CodeBlock generateMethodCode(CodeWarnings codeWarnings,
ClassName targetClassName, RuntimeHints hints) {
CodeBlock.Builder code = CodeBlock.builder();
for (AutowiredElement autowiredElement : this.autowiredElements) {
code.addStatement(generateMethodStatementForElement(
targetClassName, autowiredElement, hints));
codeWarnings, targetClassName, autowiredElement, hints));
}
code.addStatement("return $L", INSTANCE_PARAMETER);
return code.build();
}
private CodeBlock generateMethodStatementForElement(ClassName targetClassName,
AutowiredElement autowiredElement, RuntimeHints hints) {
private CodeBlock generateMethodStatementForElement(CodeWarnings codeWarnings,
ClassName targetClassName, AutowiredElement autowiredElement, RuntimeHints hints) {
Member member = autowiredElement.getMember();
boolean required = autowiredElement.required;
if (member instanceof Field field) {
return generateMethodStatementForField(
targetClassName, field, required, hints);
codeWarnings, targetClassName, field, required, hints);
}
if (member instanceof Method method) {
return generateMethodStatementForMethod(
targetClassName, method, required, hints);
codeWarnings, targetClassName, method, required, hints);
}
throw new IllegalStateException(
"Unsupported member type " + member.getClass().getName());
}
private CodeBlock generateMethodStatementForField(ClassName targetClassName,
Field field, boolean required, RuntimeHints hints) {
private CodeBlock generateMethodStatementForField(CodeWarnings codeWarnings,
ClassName targetClassName, Field field, boolean required, RuntimeHints hints) {
hints.reflection().registerField(field);
CodeBlock resolver = CodeBlock.of("$T.$L($S)",
@@ -1033,18 +1039,22 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
return CodeBlock.of("$L.resolveAndSet($L, $L)", resolver,
REGISTERED_BEAN_PARAMETER, INSTANCE_PARAMETER);
}
return CodeBlock.of("$L.$L = $L.resolve($L)", INSTANCE_PARAMETER,
field.getName(), resolver, REGISTERED_BEAN_PARAMETER);
else {
codeWarnings.detectDeprecation(field);
return CodeBlock.of("$L.$L = $L.resolve($L)", INSTANCE_PARAMETER,
field.getName(), resolver, REGISTERED_BEAN_PARAMETER);
}
}
private CodeBlock generateMethodStatementForMethod(ClassName targetClassName,
Method method, boolean required, RuntimeHints hints) {
private CodeBlock generateMethodStatementForMethod(CodeWarnings codeWarnings,
ClassName targetClassName, Method method, boolean required, RuntimeHints hints) {
CodeBlock.Builder code = CodeBlock.builder();
code.add("$T.$L", AutowiredMethodArgumentsResolver.class,
(!required ? "forMethod" : "forRequiredMethod"));
code.add("($S", method.getName());
if (method.getParameterCount() > 0) {
codeWarnings.detectDeprecation(method.getParameterTypes());
code.add(", $L", generateParameterTypesCode(method.getParameterTypes()));
}
code.add(")");
@@ -1054,6 +1064,7 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
code.add(".resolveAndInvoke($L, $L)", REGISTERED_BEAN_PARAMETER, INSTANCE_PARAMETER);
}
else {
codeWarnings.detectDeprecation(method);
hints.reflection().registerMethod(method, ExecutableMode.INTROSPECT);
CodeBlock arguments = new AutowiredArgumentsCodeGenerator(this.target,
method).generateCode(method.getParameterTypes());

View File

@@ -21,12 +21,16 @@ import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.StringJoiner;
import java.util.function.Consumer;
import java.util.stream.Stream;
import org.springframework.core.ResolvableType;
import org.springframework.javapoet.AnnotationSpec;
import org.springframework.javapoet.AnnotationSpec.Builder;
import org.springframework.javapoet.CodeBlock;
import org.springframework.javapoet.FieldSpec;
import org.springframework.javapoet.MethodSpec;
import org.springframework.javapoet.TypeSpec;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
@@ -38,7 +42,7 @@ import org.springframework.util.ClassUtils;
* @since 6.1
* @see SuppressWarnings
*/
class CodeWarnings {
public class CodeWarnings {
private final Set<String> warnings = new LinkedHashSet<>();
@@ -99,10 +103,31 @@ class CodeWarnings {
* @param method the method to update
*/
public void suppress(MethodSpec.Builder method) {
if (this.warnings.isEmpty()) {
return;
suppress(annotationBuilder -> method.addAnnotation(annotationBuilder.build()));
}
/**
* Include {@link SuppressWarnings} on the specified type if necessary.
* @param type the type to update
*/
public void suppress(TypeSpec.Builder type) {
suppress(annotationBuilder -> type.addAnnotation(annotationBuilder.build()));
}
/**
* Consume the builder for {@link SuppressWarnings} if necessary. If this
* instance has no warnings registered, the consumer is not invoked.
* @param annotationSpec a consumer of the {@link AnnotationSpec.Builder}
* @see MethodSpec.Builder#addAnnotation(AnnotationSpec)
* @see TypeSpec.Builder#addAnnotation(AnnotationSpec)
* @see FieldSpec.Builder#addAnnotation(AnnotationSpec)
*/
protected void suppress(Consumer<AnnotationSpec.Builder> annotationSpec) {
if (!this.warnings.isEmpty()) {
Builder annotation = AnnotationSpec.builder(SuppressWarnings.class)
.addMember("value", generateValueCode());
annotationSpec.accept(annotation);
}
method.addAnnotation(buildAnnotationSpec());
}
/**
@@ -134,11 +159,6 @@ class CodeWarnings {
}
}
private AnnotationSpec buildAnnotationSpec() {
return AnnotationSpec.builder(SuppressWarnings.class)
.addMember("value", generateValueCode()).build();
}
private CodeBlock generateValueCode() {
if (this.warnings.size() == 1) {
return CodeBlock.of("$S", this.warnings.iterator().next());