From b6a246989f06ed92b4d21986b84396580b5a37d3 Mon Sep 17 00:00:00 2001 From: Sam Brannen <104798+sbrannen@users.noreply.github.com> Date: Tue, 7 Apr 2026 18:16:09 +0200 Subject: [PATCH] Use ClassLoader for method or field in MergedAnnotation Prior to this commit, the `return` keyword was missing in TypeMappedAnnotation's getClassLoader() implementation, which prevented the ClassLoader of the Member (Method or Field) from being used. This commit fixes that by adding the missing `return` keyword and adds a test using a custom ClassLoader to verify the correct behavior. Closes gh-36606 (cherry picked from commit f3b6c222f98f152643a006d0295a4324050f5c3e) --- .../core/annotation/TypeMappedAnnotation.java | 2 +- .../annotation/TypeMappedAnnotationTests.java | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/spring-core/src/main/java/org/springframework/core/annotation/TypeMappedAnnotation.java b/spring-core/src/main/java/org/springframework/core/annotation/TypeMappedAnnotation.java index 749275c8d1c..19edd730df8 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/TypeMappedAnnotation.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/TypeMappedAnnotation.java @@ -595,7 +595,7 @@ final class TypeMappedAnnotation extends AbstractMergedAnn return clazz.getClassLoader(); } if (this.source instanceof Member member) { - member.getDeclaringClass().getClassLoader(); + return member.getDeclaringClass().getClassLoader(); } } return null; diff --git a/spring-core/src/test/java/org/springframework/core/annotation/TypeMappedAnnotationTests.java b/spring-core/src/test/java/org/springframework/core/annotation/TypeMappedAnnotationTests.java index 66b995a78be..dec60d5e485 100644 --- a/spring-core/src/test/java/org/springframework/core/annotation/TypeMappedAnnotationTests.java +++ b/spring-core/src/test/java/org/springframework/core/annotation/TypeMappedAnnotationTests.java @@ -20,12 +20,15 @@ import java.io.InputStream; import java.lang.annotation.Annotation; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.Method; import java.util.Collections; import java.util.HashMap; import java.util.Map; import org.junit.jupiter.api.Test; +import org.springframework.core.OverridingClassLoader; + import static org.assertj.core.api.Assertions.assertThat; /** @@ -109,6 +112,23 @@ class TypeMappedAnnotationTests { assertThat(annotation.getClass("classValue")).isEqualTo(InputStream.class); } + @Test // gh-36606 + void adaptFromStringToClassWithMemberSourceUsesMemberClassLoader() throws Exception { + OverridingClassLoader classLoader = new OverridingClassLoader(getClass().getClassLoader()) { + @Override + protected boolean isEligibleForOverriding(String className) { + return ClassAttributes.class.getName().equals(className); + } + }; + Class sourceClass = classLoader.loadClass(ClassAttributes.class.getName()); + Method sourceMethod = sourceClass.getDeclaredMethod("classValue"); + + MergedAnnotation annotation = TypeMappedAnnotation.of(null, sourceMethod, + ClassAttributes.class, Map.of("classValue", sourceClass.getName())); + + assertThat(annotation.getClass("classValue").getClassLoader()).isSameAs(classLoader); + } + @Test void adaptFromStringArrayToClassArray() { MergedAnnotation annotation = TypeMappedAnnotation.of(null, null, ClassAttributes.class,