From 819d4256b7984fdec58840a56b82e411bc53c9c9 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Sat, 19 Feb 2022 17:25:50 +0100 Subject: [PATCH] Remove deprecated "enclosing classes" search strategy for MergedAnnotations Closes gh-28080 --- .../core/annotation/AnnotationsScanner.java | 47 ++++--------------- .../core/annotation/MergedAnnotations.java | 16 +------ .../annotation/AnnotationsScannerTests.java | 26 ---------- .../annotation/MergedAnnotationsTests.java | 16 ------- 4 files changed, 12 insertions(+), 93 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationsScanner.java b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationsScanner.java index fa90a703b4e..4b8a86af808 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationsScanner.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationsScanner.java @@ -99,9 +99,8 @@ abstract class AnnotationsScanner { return switch (searchStrategy) { case DIRECT -> processElement(context, source, processor); case INHERITED_ANNOTATIONS -> processClassInheritedAnnotations(context, source, searchStrategy, processor); - case SUPERCLASS -> processClassHierarchy(context, source, processor, false, false); - case TYPE_HIERARCHY -> processClassHierarchy(context, source, processor, true, false); - case TYPE_HIERARCHY_AND_ENCLOSING_CLASSES -> processClassHierarchy(context, source, processor, true, true); + case SUPERCLASS -> processClassHierarchy(context, source, processor, false); + case TYPE_HIERARCHY -> processClassHierarchy(context, source, processor, true); }; } @@ -161,15 +160,14 @@ abstract class AnnotationsScanner { @Nullable private static R processClassHierarchy(C context, Class source, - AnnotationsProcessor processor, boolean includeInterfaces, boolean includeEnclosing) { + AnnotationsProcessor processor, boolean includeInterfaces) { - return processClassHierarchy(context, new int[] {0}, source, processor, - includeInterfaces, includeEnclosing); + return processClassHierarchy(context, new int[] {0}, source, processor, includeInterfaces); } @Nullable private static R processClassHierarchy(C context, int[] aggregateIndex, Class source, - AnnotationsProcessor processor, boolean includeInterfaces, boolean includeEnclosing) { + AnnotationsProcessor processor, boolean includeInterfaces) { try { R result = processor.doWithAggregate(context, aggregateIndex[0]); @@ -188,7 +186,7 @@ abstract class AnnotationsScanner { if (includeInterfaces) { for (Class interfaceType : source.getInterfaces()) { R interfacesResult = processClassHierarchy(context, aggregateIndex, - interfaceType, processor, true, includeEnclosing); + interfaceType, processor, true); if (interfacesResult != null) { return interfacesResult; } @@ -197,31 +195,11 @@ abstract class AnnotationsScanner { Class superclass = source.getSuperclass(); if (superclass != Object.class && superclass != null) { R superclassResult = processClassHierarchy(context, aggregateIndex, - superclass, processor, includeInterfaces, includeEnclosing); + superclass, processor, includeInterfaces); if (superclassResult != null) { return superclassResult; } } - if (includeEnclosing) { - // Since merely attempting to load the enclosing class may result in - // automatic loading of sibling nested classes that in turn results - // in an exception such as NoClassDefFoundError, we wrap the following - // in its own dedicated try-catch block in order not to preemptively - // halt the annotation scanning process. - try { - Class enclosingClass = source.getEnclosingClass(); - if (enclosingClass != null) { - R enclosingResult = processClassHierarchy(context, aggregateIndex, - enclosingClass, processor, includeInterfaces, true); - if (enclosingResult != null) { - return enclosingResult; - } - } - } - catch (Throwable ex) { - AnnotationUtils.handleIntrospectionFailure(source, ex); - } - } } catch (Throwable ex) { AnnotationUtils.handleIntrospectionFailure(source, ex); @@ -238,8 +216,7 @@ abstract class AnnotationsScanner { case DIRECT, INHERITED_ANNOTATIONS -> processMethodInheritedAnnotations(context, source, processor); case SUPERCLASS -> processMethodHierarchy(context, new int[]{0}, source.getDeclaringClass(), processor, source, false); - case TYPE_HIERARCHY, TYPE_HIERARCHY_AND_ENCLOSING_CLASSES -> processMethodHierarchy(context, new int[]{0}, - source.getDeclaringClass(), + case TYPE_HIERARCHY -> processMethodHierarchy(context, new int[]{0}, source.getDeclaringClass(), processor, source, true); }; } @@ -506,12 +483,8 @@ abstract class AnnotationsScanner { if (source == Object.class) { return true; } - if (source instanceof Class) { - Class sourceClass = (Class) source; - boolean noSuperTypes = (sourceClass.getSuperclass() == Object.class && - sourceClass.getInterfaces().length == 0); - return (searchStrategy == SearchStrategy.TYPE_HIERARCHY_AND_ENCLOSING_CLASSES ? noSuperTypes && - sourceClass.getEnclosingClass() == null : noSuperTypes); + if (source instanceof Class sourceClass) { + return (sourceClass.getSuperclass() == Object.class && sourceClass.getInterfaces().length == 0); } if (source instanceof Method sourceMethod) { return (Modifier.isPrivate(sourceMethod.getModifiers()) || diff --git a/spring-core/src/main/java/org/springframework/core/annotation/MergedAnnotations.java b/spring-core/src/main/java/org/springframework/core/annotation/MergedAnnotations.java index 28f7cf009a9..a488d29e875 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/MergedAnnotations.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/MergedAnnotations.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2022 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. @@ -472,20 +472,8 @@ public interface MergedAnnotations extends Iterable * superclasses and implemented interfaces. Superclass annotations do * not need to be meta-annotated with {@link Inherited @Inherited}. */ - TYPE_HIERARCHY, + TYPE_HIERARCHY - /** - * Perform a full search of the entire type hierarchy on the source - * and any enclosing classes. This strategy is similar to - * {@link #TYPE_HIERARCHY} except that {@linkplain Class#getEnclosingClass() - * enclosing classes} are also searched. Superclass annotations do not - * need to be meta-annotated with {@link Inherited @Inherited}. When - * searching a {@link Method} source, this strategy is identical to - * {@link #TYPE_HIERARCHY}. - * @deprecated as of Spring Framework 5.3.17; to be removed in Spring Framework 6.0 - */ - @Deprecated - TYPE_HIERARCHY_AND_ENCLOSING_CLASSES } } diff --git a/spring-core/src/test/java/org/springframework/core/annotation/AnnotationsScannerTests.java b/spring-core/src/test/java/org/springframework/core/annotation/AnnotationsScannerTests.java index e848090b124..dbbb4f00ceb 100644 --- a/spring-core/src/test/java/org/springframework/core/annotation/AnnotationsScannerTests.java +++ b/spring-core/src/test/java/org/springframework/core/annotation/AnnotationsScannerTests.java @@ -420,32 +420,6 @@ class AnnotationsScannerTests { assertThat(scan(source, SearchStrategy.TYPE_HIERARCHY)).containsExactly("0:TestAnnotation1"); } - @Test - @SuppressWarnings("deprecation") - void typeHierarchyWithEnclosedStrategyOnEnclosedStaticClassScansAnnotations() { - Class source = AnnotationEnclosingClassSample.EnclosedStatic.EnclosedStaticStatic.class; - assertThat(scan(source, SearchStrategy.TYPE_HIERARCHY_AND_ENCLOSING_CLASSES)) - .containsExactly("0:EnclosedThree", "1:EnclosedTwo", "2:EnclosedOne"); - } - - @Test - @SuppressWarnings("deprecation") - void typeHierarchyWithEnclosedStrategyOnEnclosedInnerClassScansAnnotations() { - Class source = AnnotationEnclosingClassSample.EnclosedInner.EnclosedInnerInner.class; - assertThat(scan(source, SearchStrategy.TYPE_HIERARCHY_AND_ENCLOSING_CLASSES)) - .containsExactly("0:EnclosedThree", "1:EnclosedTwo", "2:EnclosedOne"); - } - - @Test - @SuppressWarnings("deprecation") - void typeHierarchyWithEnclosedStrategyOnMethodHierarchyUsesTypeHierarchyScan() { - Method source = methodFrom(WithHierarchy.class); - assertThat(scan(source, SearchStrategy.TYPE_HIERARCHY_AND_ENCLOSING_CLASSES)).containsExactly( - "0:TestAnnotation1", "1:TestAnnotation5", "1:TestInheritedAnnotation5", - "2:TestAnnotation6", "3:TestAnnotation2", "3:TestInheritedAnnotation2", - "4:TestAnnotation3", "5:TestAnnotation4"); - } - @Test void scanWhenProcessorReturnsFromDoWithAggregateExitsEarly() { String result = AnnotationsScanner.scan(this, WithSingleSuperclass.class, diff --git a/spring-core/src/test/java/org/springframework/core/annotation/MergedAnnotationsTests.java b/spring-core/src/test/java/org/springframework/core/annotation/MergedAnnotationsTests.java index 53e82bf4a61..5c754da93e0 100644 --- a/spring-core/src/test/java/org/springframework/core/annotation/MergedAnnotationsTests.java +++ b/spring-core/src/test/java/org/springframework/core/annotation/MergedAnnotationsTests.java @@ -710,22 +710,6 @@ class MergedAnnotationsTests { Transactional.class)).hasSize(1); } - @Test - @SuppressWarnings("deprecation") - void streamTypeHierarchyAndEnclosingClassesFromNonAnnotatedInnerClassWithAnnotatedEnclosingClass() { - Stream> classes = MergedAnnotations.from(AnnotatedClass.NonAnnotatedInnerClass.class, - SearchStrategy.TYPE_HIERARCHY_AND_ENCLOSING_CLASSES).stream().map(MergedAnnotation::getType); - assertThat(classes).containsExactly(Component.class, Indexed.class); - } - - @Test - @SuppressWarnings("deprecation") - void streamTypeHierarchyAndEnclosingClassesFromNonAnnotatedStaticNestedClassWithAnnotatedEnclosingClass() { - Stream> classes = MergedAnnotations.from(AnnotatedClass.NonAnnotatedStaticNestedClass.class, - SearchStrategy.TYPE_HIERARCHY_AND_ENCLOSING_CLASSES).stream().map(MergedAnnotation::getType); - assertThat(classes).containsExactly(Component.class, Indexed.class); - } - @Test void getFromMethodWithMethodAnnotationOnLeaf() throws Exception { Method method = Leaf.class.getMethod("annotatedOnLeaf");