Skip to content

Commit f26483d

Browse files
committed
Detect deprecated element in generic types
This commit updates Spring AOT to suppress a deprecation warning for a generic type that has a deprecated element. Previously we only were checking for the raw class. Closes gh-32850
1 parent 481d036 commit f26483d

File tree

4 files changed

+76
-1
lines changed

4 files changed

+76
-1
lines changed

Diff for: spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionMethodGenerator.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ private GeneratedMethod generateBeanDefinitionMethod(GenerationContext generatio
165165
this.aotContributions.forEach(aotContribution -> aotContribution.applyTo(generationContext, codeGenerator));
166166

167167
CodeWarnings codeWarnings = new CodeWarnings();
168-
codeWarnings.detectDeprecation(this.registeredBean.getBeanClass());
168+
codeWarnings.detectDeprecation(this.registeredBean.getBeanType());
169169
return generatedMethods.add("getBeanDefinition", method -> {
170170
method.addJavadoc("Get the $L definition for '$L'.",
171171
(this.registeredBean.isInnerBean() ? "inner-bean" : "bean"),

Diff for: spring-beans/src/main/java/org/springframework/beans/factory/aot/CodeWarnings.java

+22
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,12 @@
2323
import java.util.StringJoiner;
2424
import java.util.stream.Stream;
2525

26+
import org.springframework.core.ResolvableType;
2627
import org.springframework.javapoet.AnnotationSpec;
2728
import org.springframework.javapoet.CodeBlock;
2829
import org.springframework.javapoet.MethodSpec;
2930
import org.springframework.lang.Nullable;
31+
import org.springframework.util.ClassUtils;
3032

3133
/**
3234
* Helper class to register warnings that the compiler may trigger on
@@ -72,6 +74,26 @@ public CodeWarnings detectDeprecation(Stream<AnnotatedElement> elements) {
7274
return this;
7375
}
7476

77+
/**
78+
* Detect the presence of {@link Deprecated} on the signature of the
79+
* specified {@link ResolvableType}.
80+
* @param resolvableType a type signature
81+
* @return {@code this} instance
82+
*/
83+
public CodeWarnings detectDeprecation(ResolvableType resolvableType) {
84+
if (ResolvableType.NONE.equals(resolvableType)) {
85+
return this;
86+
}
87+
Class<?> type = ClassUtils.getUserClass(resolvableType.toClass());
88+
detectDeprecation(type);
89+
if (resolvableType.hasGenerics() && !resolvableType.hasUnresolvableGenerics()) {
90+
for (ResolvableType generic : resolvableType.getGenerics()) {
91+
detectDeprecation(generic);
92+
}
93+
}
94+
return this;
95+
}
96+
7597
/**
7698
* Include {@link SuppressWarnings} on the specified method if necessary.
7799
* @param method the method to update

Diff for: spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanDefinitionMethodGeneratorTests.java

+13
Original file line numberDiff line numberDiff line change
@@ -782,6 +782,19 @@ void generateBeanDefinitionMethodWithDeprecatedTargetClass() {
782782
compileAndCheckWarnings(method);
783783
}
784784

785+
@Test
786+
void generateBeanDefinitionMethodWithDeprecatedGenericElementInTargetClass() {
787+
RootBeanDefinition beanDefinition = new RootBeanDefinition();
788+
beanDefinition.setTargetType(ResolvableType.forClassWithGenerics(GenericBean.class, DeprecatedBean.class));
789+
RegisteredBean registeredBean = registerBean(beanDefinition);
790+
BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator(
791+
methodGeneratorFactory, registeredBean, null,
792+
Collections.emptyList());
793+
MethodReference method = generator.generateBeanDefinitionMethod(
794+
generationContext, beanRegistrationsCode);
795+
compileAndCheckWarnings(method);
796+
}
797+
785798
private void compileAndCheckWarnings(MethodReference methodReference) {
786799
assertThatNoException().isThrownBy(() -> compile(TEST_COMPILER, methodReference,
787800
((instanceSupplier, compiled) -> {})));

Diff for: spring-beans/src/test/java/org/springframework/beans/factory/aot/CodeWarningsTests.java

+40
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,21 @@
1717
package org.springframework.beans.factory.aot;
1818

1919
import java.util.function.Consumer;
20+
import java.util.stream.Stream;
2021

2122
import javax.lang.model.element.Modifier;
2223

2324
import org.junit.jupiter.api.Test;
25+
import org.junit.jupiter.params.ParameterizedTest;
26+
import org.junit.jupiter.params.provider.Arguments;
27+
import org.junit.jupiter.params.provider.MethodSource;
2428

2529
import org.springframework.aot.test.generate.TestGenerationContext;
30+
import org.springframework.beans.testfixture.beans.GenericBean;
2631
import org.springframework.beans.testfixture.beans.factory.aot.DeferredTypeBuilder;
2732
import org.springframework.beans.testfixture.beans.factory.generator.deprecation.DeprecatedBean;
2833
import org.springframework.beans.testfixture.beans.factory.generator.deprecation.DeprecatedForRemovalBean;
34+
import org.springframework.core.ResolvableType;
2935
import org.springframework.core.test.tools.Compiled;
3036
import org.springframework.core.test.tools.TestCompiler;
3137
import org.springframework.javapoet.MethodSpec;
@@ -98,6 +104,40 @@ void detectDeprecationOnAnnotatedElementWithDeprecatedForRemoval() {
98104
assertThat(this.codeWarnings.getWarnings()).containsExactly("removal");
99105
}
100106

107+
@ParameterizedTest
108+
@MethodSource("resolvableTypesWithDeprecated")
109+
void detectDeprecationOnResolvableTypeWithDeprecated(ResolvableType resolvableType) {
110+
this.codeWarnings.detectDeprecation(resolvableType);
111+
assertThat(this.codeWarnings.getWarnings()).containsExactly("deprecation");
112+
}
113+
114+
@SuppressWarnings("deprecation")
115+
static Stream<Arguments> resolvableTypesWithDeprecated() {
116+
return Stream.of(
117+
Arguments.of(ResolvableType.forClass(DeprecatedBean.class)),
118+
Arguments.of(ResolvableType.forClassWithGenerics(GenericBean.class, DeprecatedBean.class)),
119+
Arguments.of(ResolvableType.forClassWithGenerics(GenericBean.class,
120+
ResolvableType.forClassWithGenerics(GenericBean.class, DeprecatedBean.class)))
121+
);
122+
}
123+
124+
@ParameterizedTest
125+
@MethodSource("resolvableTypesWithDeprecatedForRemoval")
126+
void detectDeprecationOnResolvableTypeWithDeprecatedForRemoval(ResolvableType resolvableType) {
127+
this.codeWarnings.detectDeprecation(resolvableType);
128+
assertThat(this.codeWarnings.getWarnings()).containsExactly("removal");
129+
}
130+
131+
@SuppressWarnings("removal")
132+
static Stream<Arguments> resolvableTypesWithDeprecatedForRemoval() {
133+
return Stream.of(
134+
Arguments.of(ResolvableType.forClass(DeprecatedForRemovalBean.class)),
135+
Arguments.of(ResolvableType.forClassWithGenerics(GenericBean.class, DeprecatedForRemovalBean.class)),
136+
Arguments.of(ResolvableType.forClassWithGenerics(GenericBean.class,
137+
ResolvableType.forClassWithGenerics(GenericBean.class, DeprecatedForRemovalBean.class)))
138+
);
139+
}
140+
101141
@Test
102142
void toStringIncludeWarnings() {
103143
this.codeWarnings.register("deprecation");

0 commit comments

Comments
 (0)