From 7b8d8693ddbaf0a2830cce19e0441e786cc5794f Mon Sep 17 00:00:00 2001 From: Sam Brannen <104798+sbrannen@users.noreply.github.com> Date: Wed, 1 Apr 2026 10:08:53 +0200 Subject: [PATCH] Fix AnnotationMetadata tests in Eclipse IDE Since commit 89391fd94c, the getClassAttributeWhenUnknownClass() methods in SimpleAnnotationMetadataTests and DefaultAnnotationMetadataTests have failed in Eclipse, since the JSR-305 JAR is always on the test runtime classpath in Eclipse. To address that, this commit introduces a FilteringClassLoader in both test classes which mimics the test runtime behavior in the Gradle build. See gh-36432 --- .../DefaultAnnotationMetadataTests.java | 36 +++++++++++++--- .../SimpleAnnotationMetadataTests.java | 41 +++++++++++++++---- 2 files changed, 62 insertions(+), 15 deletions(-) diff --git a/spring-core/src/test/java/org/springframework/core/type/classreading/DefaultAnnotationMetadataTests.java b/spring-core/src/test/java/org/springframework/core/type/classreading/DefaultAnnotationMetadataTests.java index b91f23a45b4..58f64bb3da5 100644 --- a/spring-core/src/test/java/org/springframework/core/type/classreading/DefaultAnnotationMetadataTests.java +++ b/spring-core/src/test/java/org/springframework/core/type/classreading/DefaultAnnotationMetadataTests.java @@ -22,6 +22,7 @@ import java.lang.annotation.RetentionPolicy; import org.junit.jupiter.api.Test; +import org.springframework.core.OverridingClassLoader; import org.springframework.core.type.AbstractAnnotationMetadataTests; import org.springframework.core.type.AnnotationMetadata; @@ -50,21 +51,44 @@ class DefaultAnnotationMetadataTests extends AbstractAnnotationMetadataTests { } @Test - void getClassAttributeWhenUnknownClass() { - var annotation = get(WithClassMissingFromClasspath.class).getAnnotations().get(ClassAttributes.class); - assertThat(annotation.getStringArray("types")).contains("javax.annotation.meta.When"); - assertThatIllegalArgumentException().isThrownBy(() -> annotation.getClassArray("types")); + void getClassAttributeWhenUnknownClass() throws IOException { + var classLoader = new FilteringClassLoader(getClass().getClassLoader()); + var mergedAnnotation = MetadataReaderFactory.create(classLoader) + .getMetadataReader(WithClassMissingFromClasspath.class.getName()) + .getAnnotationMetadata() + .getAnnotations() + .get(ClassAttributes.class); + assertThat(mergedAnnotation.getStringArray("types")).contains("javax.annotation.meta.When"); + assertThatIllegalArgumentException().isThrownBy(() -> mergedAnnotation.getClassArray("types")); + } + + + private static class FilteringClassLoader extends OverridingClassLoader { + + FilteringClassLoader(ClassLoader parent) { + super(parent); + } + + @Override + protected boolean isEligibleForOverriding(String className) { + return className.startsWith("javax.annotation."); + } + + @Override + protected Class loadClassForOverriding(String name) throws ClassNotFoundException { + throw new ClassNotFoundException(name); + } } @ClassAttributes(types = {javax.annotation.meta.When.class}) @javax.annotation.Nonnull(when = javax.annotation.meta.When.MAYBE) - public static class WithClassMissingFromClasspath { + static class WithClassMissingFromClasspath { } @Retention(RetentionPolicy.RUNTIME) - public @interface ClassAttributes { + @interface ClassAttributes { Class[] types(); } diff --git a/spring-core/src/test/java/org/springframework/core/type/classreading/SimpleAnnotationMetadataTests.java b/spring-core/src/test/java/org/springframework/core/type/classreading/SimpleAnnotationMetadataTests.java index ad6a8b1e2cc..28432205943 100644 --- a/spring-core/src/test/java/org/springframework/core/type/classreading/SimpleAnnotationMetadataTests.java +++ b/spring-core/src/test/java/org/springframework/core/type/classreading/SimpleAnnotationMetadataTests.java @@ -22,6 +22,7 @@ import java.lang.annotation.RetentionPolicy; import org.junit.jupiter.api.Test; +import org.springframework.core.OverridingClassLoader; import org.springframework.core.type.AbstractAnnotationMetadataTests; import org.springframework.core.type.AnnotationMetadata; @@ -40,9 +41,8 @@ class SimpleAnnotationMetadataTests extends AbstractAnnotationMetadataTests { @Override protected AnnotationMetadata get(Class source) { try { - return new SimpleMetadataReaderFactory( - source.getClassLoader()).getMetadataReader( - source.getName()).getAnnotationMetadata(); + return new SimpleMetadataReaderFactory(source.getClassLoader()) + .getMetadataReader(source.getName()).getAnnotationMetadata(); } catch (IOException ex) { throw new IllegalStateException(ex); @@ -50,21 +50,44 @@ class SimpleAnnotationMetadataTests extends AbstractAnnotationMetadataTests { } @Test - void getClassAttributeWhenUnknownClass() { - var annotation = get(WithClassMissingFromClasspath.class).getAnnotations().get(ClassAttributes.class); - assertThat(annotation.getStringArray("types")).contains("javax.annotation.meta.When"); - assertThatIllegalArgumentException().isThrownBy(() -> annotation.getClassArray("types")); + void getClassAttributeWhenUnknownClass() throws IOException { + var classLoader = new FilteringClassLoader(getClass().getClassLoader()); + var mergedAnnotation = new SimpleMetadataReaderFactory(classLoader) + .getMetadataReader(WithClassMissingFromClasspath.class.getName()) + .getAnnotationMetadata() + .getAnnotations() + .get(ClassAttributes.class); + assertThat(mergedAnnotation.getStringArray("types")).contains("javax.annotation.meta.When"); + assertThatIllegalArgumentException().isThrownBy(() -> mergedAnnotation.getClassArray("types")); + } + + + private static class FilteringClassLoader extends OverridingClassLoader { + + FilteringClassLoader(ClassLoader parent) { + super(parent); + } + + @Override + protected boolean isEligibleForOverriding(String className) { + return className.startsWith("javax.annotation."); + } + + @Override + protected Class loadClassForOverriding(String name) throws ClassNotFoundException { + throw new ClassNotFoundException(name); + } } @ClassAttributes(types = {javax.annotation.meta.When.class}) @javax.annotation.Nonnull(when = javax.annotation.meta.When.MAYBE) - public static class WithClassMissingFromClasspath { + static class WithClassMissingFromClasspath { } @Retention(RetentionPolicy.RUNTIME) - public @interface ClassAttributes { + @interface ClassAttributes { Class[] types(); }