Skip to content

Commit 233eb7f

Browse files
committed
Fix StringIndexOutOfBoundsException with Class-File metadata
Prior to this commit, the new `ClassFileAnnotationMetadata` would fail when reading `Class<T>` annotation attributes when values are primitive types. This commit uses `java.lang.constant.ClassDesc` to better parse type descriptors from the bytecode. Fixes gh-24882
1 parent 18756c0 commit 233eb7f

File tree

2 files changed

+20
-2
lines changed

2 files changed

+20
-2
lines changed

spring-core/src/main/java24/org/springframework/core/type/classreading/ClassFileAnnotationMetadata.java

+5-2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.lang.classfile.AnnotationElement;
2222
import java.lang.classfile.AnnotationValue;
2323
import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute;
24+
import java.lang.constant.ClassDesc;
2425
import java.lang.reflect.Array;
2526
import java.util.Collections;
2627
import java.util.LinkedHashMap;
@@ -36,6 +37,7 @@
3637
import org.springframework.core.annotation.MergedAnnotation;
3738
import org.springframework.core.annotation.MergedAnnotations;
3839
import org.springframework.util.ClassUtils;
40+
import org.springframework.util.StringUtils;
3941

4042
/**
4143
* Parse {@link RuntimeVisibleAnnotationsAttribute} into {@link MergedAnnotations}
@@ -97,8 +99,9 @@ static MergedAnnotations createMergedAnnotations(String className, RuntimeVisibl
9799
}
98100

99101
private static String fromTypeDescriptor(String descriptor) {
100-
return descriptor.substring(1, descriptor.length() - 1)
101-
.replace('/', '.');
102+
ClassDesc classDesc = ClassDesc.ofDescriptor(descriptor);
103+
return classDesc.isPrimitive() ? "java.lang." + StringUtils.capitalize(classDesc.displayName()) :
104+
classDesc.packageName() + "." + classDesc.displayName();
102105
}
103106

104107
private static Object parseArrayValue(String className, @org.jetbrains.annotations.Nullable ClassLoader classLoader, AnnotationValue.OfArray arrayValue) {

spring-core/src/test/java/org/springframework/core/type/AbstractAnnotationMetadataTests.java

+15
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,14 @@ void getComplexAttributeTypesReturnsAllWithKotlinMetadata() {
308308
assertThat(attributes.get("mv").get(0)).isEqualTo(values);
309309
}
310310

311+
@Test
312+
void getAnnotationAttributeVoidType() {
313+
MultiValueMap<String, Object> attributes =
314+
get(WithVoidType.class).getAllAnnotationAttributes(ComplexAttributes.class.getName());
315+
assertThat(attributes).containsOnlyKeys("names", "count", "type", "subAnnotation");
316+
assertThat(attributes.get("type")).containsAnyOf(Void.class, void.class);
317+
}
318+
311319
@Test
312320
void getRepeatableReturnsAttributes() {
313321
MultiValueMap<String, Object> attributes =
@@ -445,12 +453,19 @@ public static class WithMetaAnnotationAttributes {
445453

446454
}
447455

456+
448457
@ComplexAttributes(names = {"first", "second"}, count = TestEnum.ONE,
449458
type = TestEnum.class, subAnnotation = @SubAnnotation(name="spring"))
450459
@Metadata(mv = {42})
451460
public static class WithComplexAttributeTypes {
452461
}
453462

463+
@ComplexAttributes(names = "void", count = TestEnum.ONE, type = void.class,
464+
subAnnotation = @SubAnnotation(name="spring"))
465+
public static class WithVoidType {
466+
467+
}
468+
454469
@Retention(RetentionPolicy.RUNTIME)
455470
public @interface ComplexAttributes {
456471

0 commit comments

Comments
 (0)