Browse Source

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
pull/34884/head
Brian Clozel 8 months ago
parent
commit
233eb7f0aa
  1. 7
      spring-core/src/main/java24/org/springframework/core/type/classreading/ClassFileAnnotationMetadata.java
  2. 15
      spring-core/src/test/java/org/springframework/core/type/AbstractAnnotationMetadataTests.java

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

@ -21,6 +21,7 @@ import java.lang.classfile.Annotation; @@ -21,6 +21,7 @@ import java.lang.classfile.Annotation;
import java.lang.classfile.AnnotationElement;
import java.lang.classfile.AnnotationValue;
import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute;
import java.lang.constant.ClassDesc;
import java.lang.reflect.Array;
import java.util.Collections;
import java.util.LinkedHashMap;
@ -36,6 +37,7 @@ import org.springframework.core.annotation.AnnotationFilter; @@ -36,6 +37,7 @@ import org.springframework.core.annotation.AnnotationFilter;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
/**
* Parse {@link RuntimeVisibleAnnotationsAttribute} into {@link MergedAnnotations}
@ -97,8 +99,9 @@ abstract class ClassFileAnnotationMetadata { @@ -97,8 +99,9 @@ abstract class ClassFileAnnotationMetadata {
}
private static String fromTypeDescriptor(String descriptor) {
return descriptor.substring(1, descriptor.length() - 1)
.replace('/', '.');
ClassDesc classDesc = ClassDesc.ofDescriptor(descriptor);
return classDesc.isPrimitive() ? "java.lang." + StringUtils.capitalize(classDesc.displayName()) :
classDesc.packageName() + "." + classDesc.displayName();
}
private static Object parseArrayValue(String className, @org.jetbrains.annotations.Nullable ClassLoader classLoader, AnnotationValue.OfArray arrayValue) {

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

@ -308,6 +308,14 @@ public abstract class AbstractAnnotationMetadataTests { @@ -308,6 +308,14 @@ public abstract class AbstractAnnotationMetadataTests {
assertThat(attributes.get("mv").get(0)).isEqualTo(values);
}
@Test
void getAnnotationAttributeVoidType() {
MultiValueMap<String, Object> attributes =
get(WithVoidType.class).getAllAnnotationAttributes(ComplexAttributes.class.getName());
assertThat(attributes).containsOnlyKeys("names", "count", "type", "subAnnotation");
assertThat(attributes.get("type")).containsAnyOf(Void.class, void.class);
}
@Test
void getRepeatableReturnsAttributes() {
MultiValueMap<String, Object> attributes =
@ -445,12 +453,19 @@ public abstract class AbstractAnnotationMetadataTests { @@ -445,12 +453,19 @@ public abstract class AbstractAnnotationMetadataTests {
}
@ComplexAttributes(names = {"first", "second"}, count = TestEnum.ONE,
type = TestEnum.class, subAnnotation = @SubAnnotation(name="spring"))
@Metadata(mv = {42})
public static class WithComplexAttributeTypes {
}
@ComplexAttributes(names = "void", count = TestEnum.ONE, type = void.class,
subAnnotation = @SubAnnotation(name="spring"))
public static class WithVoidType {
}
@Retention(RetentionPolicy.RUNTIME)
public @interface ComplexAttributes {

Loading…
Cancel
Save