diff --git a/spring-core/src/main/java24/org/springframework/core/type/classreading/ClassFileAnnotationMetadata.java b/spring-core/src/main/java24/org/springframework/core/type/classreading/ClassFileAnnotationMetadata.java index 248600ec6cd..5cfc0ed49b5 100644 --- a/spring-core/src/main/java24/org/springframework/core/type/classreading/ClassFileAnnotationMetadata.java +++ b/spring-core/src/main/java24/org/springframework/core/type/classreading/ClassFileAnnotationMetadata.java @@ -25,6 +25,7 @@ import java.lang.constant.ClassDesc; import java.lang.reflect.Array; import java.util.Collections; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; @@ -86,7 +87,7 @@ abstract class ClassFileAnnotationMetadata { return createMergedAnnotation(className, annotationValue.annotation(), classLoader); } case AnnotationValue.OfClass classValue -> { - return fromTypeDescriptor(classValue.className().stringValue()); + return loadClass(classValue.className().stringValue(), classLoader); } case AnnotationValue.OfEnum enumValue -> { return parseEnum(enumValue, classLoader); @@ -103,6 +104,16 @@ abstract class ClassFileAnnotationMetadata { classDesc.packageName() + "." + classDesc.displayName(); } + private static Class loadClass(String className, @Nullable ClassLoader classLoader) { + try { + String name = fromTypeDescriptor(className); + return ClassUtils.forName(name, classLoader); + } + catch (ClassNotFoundException ex) { + return Object.class; + } + } + private static Object parseArrayValue(String className, @Nullable ClassLoader classLoader, AnnotationValue.OfArray arrayValue) { if (arrayValue.values().isEmpty()) { return new Object[0]; @@ -119,10 +130,10 @@ abstract class ClassFileAnnotationMetadata { return stream.map(AnnotationValue.OfLong.class::cast).mapToLong(AnnotationValue.OfLong::longValue).toArray(); } default -> { - Object firstResolvedValue = readAnnotationValue(className, arrayValue.values().getFirst(), classLoader); + Class arrayElementType = resolveArrayElementType(arrayValue.values(), classLoader); return stream .map(rawValue -> readAnnotationValue(className, rawValue, classLoader)) - .toArray(s -> (Object[]) Array.newInstance(firstResolvedValue.getClass(), s)); + .toArray(s -> (Object[]) Array.newInstance(arrayElementType, s)); } } } @@ -139,6 +150,28 @@ abstract class ClassFileAnnotationMetadata { } } + private static Class resolveArrayElementType(List values, @Nullable ClassLoader classLoader) { + AnnotationValue firstValue = values.getFirst(); + switch (firstValue) { + case AnnotationValue.OfConstant constantValue -> { + return constantValue.resolvedValue().getClass(); + } + case AnnotationValue.OfAnnotation _ -> { + return MergedAnnotation.class; + } + case AnnotationValue.OfClass _ -> { + return Class.class; + } + case AnnotationValue.OfEnum enumValue -> { + return loadClass(enumValue.className().stringValue(), classLoader); + } + default -> { + return Object.class; + } + } + } + + record Source(Annotation entryName) { } diff --git a/spring-core/src/test/java/org/springframework/core/type/AbstractAnnotationMetadataTests.java b/spring-core/src/test/java/org/springframework/core/type/AbstractAnnotationMetadataTests.java index 2a99548154f..3b4b1fcf007 100644 --- a/spring-core/src/test/java/org/springframework/core/type/AbstractAnnotationMetadataTests.java +++ b/spring-core/src/test/java/org/springframework/core/type/AbstractAnnotationMetadataTests.java @@ -290,11 +290,11 @@ public abstract class AbstractAnnotationMetadataTests { void getComplexAttributeTypesReturnsAll() { MultiValueMap attributes = get(WithComplexAttributeTypes.class).getAllAnnotationAttributes(ComplexAttributes.class.getName()); - assertThat(attributes).containsOnlyKeys("names", "count", "type", "subAnnotation"); + assertThat(attributes).containsOnlyKeys("names", "count", "types", "subAnnotation"); assertThat(attributes.get("names")).hasSize(1); assertThat(attributes.get("names").get(0)).isEqualTo(new String[]{"first", "second"}); - assertThat(attributes.get("count")).containsExactlyInAnyOrder(TestEnum.ONE); - assertThat(attributes.get("type")).containsExactlyInAnyOrder(TestEnum.class); + assertThat(attributes.get("count").get(0)).isEqualTo(new TestEnum[]{TestEnum.ONE, TestEnum.TWO}); + assertThat(attributes.get("types").get(0)).isEqualTo(new Class[]{TestEnum.class}); assertThat(attributes.get("subAnnotation")).hasSize(1); } @@ -312,8 +312,8 @@ public abstract class AbstractAnnotationMetadataTests { void getAnnotationAttributeIntType() { MultiValueMap attributes = get(WithIntType.class).getAllAnnotationAttributes(ComplexAttributes.class.getName()); - assertThat(attributes).containsOnlyKeys("names", "count", "type", "subAnnotation"); - assertThat(attributes.get("type")).contains(int.class); + assertThat(attributes).containsOnlyKeys("names", "count", "types", "subAnnotation"); + assertThat(attributes.get("types").get(0)).isEqualTo(new Class[]{int.class}); } @Test @@ -454,13 +454,13 @@ public abstract class AbstractAnnotationMetadataTests { } - @ComplexAttributes(names = {"first", "second"}, count = TestEnum.ONE, - type = TestEnum.class, subAnnotation = @SubAnnotation(name="spring")) + @ComplexAttributes(names = {"first", "second"}, count = {TestEnum.ONE, TestEnum.TWO}, + types = {TestEnum.class}, subAnnotation = @SubAnnotation(name="spring")) @Metadata(mv = {42}) public static class WithComplexAttributeTypes { } - @ComplexAttributes(names = "void", count = TestEnum.ONE, type = int.class, + @ComplexAttributes(names = "void", count = TestEnum.ONE, types = int.class, subAnnotation = @SubAnnotation(name="spring")) public static class WithIntType { @@ -471,9 +471,9 @@ public abstract class AbstractAnnotationMetadataTests { String[] names(); - TestEnum count(); + TestEnum[] count(); - Class type(); + Class[] types(); SubAnnotation subAnnotation(); } @@ -484,7 +484,15 @@ public abstract class AbstractAnnotationMetadataTests { } public enum TestEnum { - ONE, TWO, THREE + ONE { + + }, + TWO { + + }, + THREE { + + } } @RepeatableAnnotation(name = "first")