From 52849819def318034015a029020d64e0aa21a0a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Thu, 25 Jul 2024 16:28:40 +0200 Subject: [PATCH] Detect deprecation on enclosing classes as well This commit improves CodeWarnings so that it detects if an enclosing class is deprecated. Previously, it would only consider the annotated element itself and the enclosing element is important for a class as it is required to refer to it. Closes gh-33273 --- .../beans/factory/aot/CodeWarnings.java | 14 ++++++- .../beans/factory/aot/CodeWarningsTests.java | 40 +++++++++++++++---- .../generator/deprecation/DeprecatedBean.java | 6 ++- .../deprecation/DeprecatedForRemovalBean.java | 5 ++- 4 files changed, 54 insertions(+), 11 deletions(-) diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/aot/CodeWarnings.java b/spring-beans/src/main/java/org/springframework/beans/factory/aot/CodeWarnings.java index fd2a42c7c1d..108c0d6cc77 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/aot/CodeWarnings.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/aot/CodeWarnings.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 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. @@ -59,7 +59,7 @@ class CodeWarnings { */ public CodeWarnings detectDeprecation(AnnotatedElement... elements) { for (AnnotatedElement element : elements) { - register(element.getAnnotation(Deprecated.class)); + registerDeprecationIfNecessary(element); } return this; } @@ -113,6 +113,16 @@ class CodeWarnings { return Collections.unmodifiableSet(this.warnings); } + private void registerDeprecationIfNecessary(@Nullable AnnotatedElement element) { + if (element == null) { + return; + } + register(element.getAnnotation(Deprecated.class)); + if (element instanceof Class type) { + registerDeprecationIfNecessary(type.getEnclosingClass()); + } + } + private void register(@Nullable Deprecated annotation) { if (annotation != null) { if (annotation.forRemoval()) { diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/aot/CodeWarningsTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/aot/CodeWarningsTests.java index fdc8a9af736..7b5db5e3447 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/aot/CodeWarningsTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/aot/CodeWarningsTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 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. @@ -97,6 +97,13 @@ class CodeWarningsTests { assertThat(this.codeWarnings.getWarnings()).containsExactly("deprecation"); } + @Test + @SuppressWarnings("deprecation") + void detectDeprecationOnAnnotatedElementWhoseEnclosingElementIsDeprecated() { + this.codeWarnings.detectDeprecation(DeprecatedBean.Nested.class); + assertThat(this.codeWarnings.getWarnings()).containsExactly("deprecation"); + } + @Test @SuppressWarnings("removal") void detectDeprecationOnAnnotatedElementWithDeprecatedForRemoval() { @@ -104,6 +111,13 @@ class CodeWarningsTests { assertThat(this.codeWarnings.getWarnings()).containsExactly("removal"); } + @Test + @SuppressWarnings("removal") + void detectDeprecationOnAnnotatedElementWhoseEnclosingElementIsDeprecatedForRemoval() { + this.codeWarnings.detectDeprecation(DeprecatedForRemovalBean.Nested.class); + assertThat(this.codeWarnings.getWarnings()).containsExactly("removal"); + } + @ParameterizedTest @MethodSource("resolvableTypesWithDeprecated") void detectDeprecationOnResolvableTypeWithDeprecated(ResolvableType resolvableType) { @@ -113,11 +127,17 @@ class CodeWarningsTests { @SuppressWarnings("deprecation") static Stream resolvableTypesWithDeprecated() { + Class deprecatedBean = DeprecatedBean.class; + Class nested = DeprecatedBean.Nested.class; return Stream.of( - Arguments.of(ResolvableType.forClass(DeprecatedBean.class)), - Arguments.of(ResolvableType.forClassWithGenerics(GenericBean.class, DeprecatedBean.class)), + Arguments.of(ResolvableType.forClass(deprecatedBean)), + Arguments.of(ResolvableType.forClass(nested)), + Arguments.of(ResolvableType.forClassWithGenerics(GenericBean.class, deprecatedBean)), + Arguments.of(ResolvableType.forClassWithGenerics(GenericBean.class, nested)), + Arguments.of(ResolvableType.forClassWithGenerics(GenericBean.class, + ResolvableType.forClassWithGenerics(GenericBean.class, deprecatedBean))), Arguments.of(ResolvableType.forClassWithGenerics(GenericBean.class, - ResolvableType.forClassWithGenerics(GenericBean.class, DeprecatedBean.class))) + ResolvableType.forClassWithGenerics(GenericBean.class, nested))) ); } @@ -130,11 +150,17 @@ class CodeWarningsTests { @SuppressWarnings("removal") static Stream resolvableTypesWithDeprecatedForRemoval() { + Class deprecatedBean = DeprecatedForRemovalBean.class; + Class nested = DeprecatedForRemovalBean.Nested.class; return Stream.of( - Arguments.of(ResolvableType.forClass(DeprecatedForRemovalBean.class)), - Arguments.of(ResolvableType.forClassWithGenerics(GenericBean.class, DeprecatedForRemovalBean.class)), + Arguments.of(ResolvableType.forClass(deprecatedBean)), + Arguments.of(ResolvableType.forClass(nested)), + Arguments.of(ResolvableType.forClassWithGenerics(GenericBean.class, deprecatedBean)), + Arguments.of(ResolvableType.forClassWithGenerics(GenericBean.class, nested)), + Arguments.of(ResolvableType.forClassWithGenerics(GenericBean.class, + ResolvableType.forClassWithGenerics(GenericBean.class, deprecatedBean))), Arguments.of(ResolvableType.forClassWithGenerics(GenericBean.class, - ResolvableType.forClassWithGenerics(GenericBean.class, DeprecatedForRemovalBean.class))) + ResolvableType.forClassWithGenerics(GenericBean.class, nested))) ); } diff --git a/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/factory/generator/deprecation/DeprecatedBean.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/factory/generator/deprecation/DeprecatedBean.java index 43ca2a4745c..a8d90235fbf 100644 --- a/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/factory/generator/deprecation/DeprecatedBean.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/factory/generator/deprecation/DeprecatedBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 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. @@ -23,4 +23,8 @@ package org.springframework.beans.testfixture.beans.factory.generator.deprecatio */ @Deprecated public class DeprecatedBean { + + // This isn't flag deprecated on purpose + public static class Nested {} + } diff --git a/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/factory/generator/deprecation/DeprecatedForRemovalBean.java b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/factory/generator/deprecation/DeprecatedForRemovalBean.java index 7f07540fb33..0d1e6b9bfae 100644 --- a/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/factory/generator/deprecation/DeprecatedForRemovalBean.java +++ b/spring-beans/src/testFixtures/java/org/springframework/beans/testfixture/beans/factory/generator/deprecation/DeprecatedForRemovalBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 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. @@ -23,4 +23,7 @@ package org.springframework.beans.testfixture.beans.factory.generator.deprecatio */ @Deprecated(forRemoval = true) public class DeprecatedForRemovalBean { + + // This isn't flag deprecated on purpose + public static class Nested {} }