Do not load concrete types in annotation metadata

This change fixes a regression introduced in the previous commit.

Closes gh-35252
This commit is contained in:
Brian Clozel
2025-08-26 21:58:15 +02:00
parent 2b7f88ee44
commit 81b4020fc6
4 changed files with 62 additions and 11 deletions
+1
View File
@@ -88,6 +88,7 @@ dependencies {
optional("org.jetbrains.kotlin:kotlin-stdlib")
optional("org.jetbrains.kotlinx:kotlinx-coroutines-core")
optional("org.jetbrains.kotlinx:kotlinx-coroutines-reactor")
testCompileOnly("com.github.ben-manes.caffeine:caffeine")
testFixturesImplementation("io.projectreactor:reactor-test")
testFixturesImplementation("org.assertj:assertj-core")
testFixturesImplementation("org.junit.jupiter:junit-jupiter")
@@ -87,7 +87,7 @@ abstract class ClassFileAnnotationMetadata {
return createMergedAnnotation(className, annotationValue.annotation(), classLoader);
}
case AnnotationValue.OfClass classValue -> {
return loadClass(classValue.className().stringValue(), classLoader);
return fromTypeDescriptor(classValue.className().stringValue());
}
case AnnotationValue.OfEnum enumValue -> {
return parseEnum(enumValue, classLoader);
@@ -105,13 +105,8 @@ abstract class ClassFileAnnotationMetadata {
}
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;
}
String name = fromTypeDescriptor(className);
return ClassUtils.resolveClassName(name, classLoader);
}
private static Object parseArrayValue(String className, @Nullable ClassLoader classLoader, AnnotationValue.OfArray arrayValue) {
@@ -160,7 +155,7 @@ abstract class ClassFileAnnotationMetadata {
return MergedAnnotation.class;
}
case AnnotationValue.OfClass _ -> {
return Class.class;
return String.class;
}
case AnnotationValue.OfEnum enumValue -> {
return loadClass(enumValue.className().stringValue(), classLoader);
@@ -16,15 +16,26 @@
package org.springframework.core.type.classreading;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.junit.jupiter.api.Test;
import org.springframework.core.type.AbstractAnnotationMetadataTests;
import org.springframework.core.type.AnnotationMetadata;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
/**
* Tests for {@link SimpleAnnotationMetadata} and
* {@link SimpleAnnotationMetadataReadingVisitor} on Java < 24,
* and for the ClassFile API variant on Java >= 24.
*
* @author Phillip Webb
* @author Brian Clozel
*/
class DefaultAnnotationMetadataTests extends AbstractAnnotationMetadataTests {
@@ -34,9 +45,25 @@ class DefaultAnnotationMetadataTests extends AbstractAnnotationMetadataTests {
return MetadataReaderFactory.create(source.getClassLoader())
.getMetadataReader(source.getName()).getAnnotationMetadata();
}
catch (Exception ex) {
catch (IOException ex) {
throw new IllegalStateException(ex);
}
}
@Test
void getClassAttributeWhenUnknownClass() {
var annotation = get(WithClassMissingFromClasspath.class).getAnnotations().get(ClassAttributes.class);
assertThat(annotation.getStringArray("types")).contains("com.github.benmanes.caffeine.cache.Caffeine");
assertThatIllegalArgumentException().isThrownBy(() -> annotation.getClassArray("types"));
}
@ClassAttributes(types = {Caffeine.class})
public static class WithClassMissingFromClasspath {
}
@Retention(RetentionPolicy.RUNTIME)
public @interface ClassAttributes {
Class<?>[] types();
}
}
@@ -16,14 +16,25 @@
package org.springframework.core.type.classreading;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.junit.jupiter.api.Test;
import org.springframework.core.type.AbstractAnnotationMetadataTests;
import org.springframework.core.type.AnnotationMetadata;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
/**
* Tests for {@link SimpleAnnotationMetadata} and
* {@link SimpleAnnotationMetadataReadingVisitor}.
*
* @author Phillip Webb
* @author Brian Clozel
*/
class SimpleAnnotationMetadataTests extends AbstractAnnotationMetadataTests {
@@ -34,9 +45,26 @@ class SimpleAnnotationMetadataTests extends AbstractAnnotationMetadataTests {
source.getClassLoader()).getMetadataReader(
source.getName()).getAnnotationMetadata();
}
catch (Exception ex) {
catch (IOException ex) {
throw new IllegalStateException(ex);
}
}
@Test
void getClassAttributeWhenUnknownClass() {
var annotation = get(WithClassMissingFromClasspath.class).getAnnotations().get(ClassAttributes.class);
assertThat(annotation.getStringArray("types")).contains("com.github.benmanes.caffeine.cache.Caffeine");
assertThatIllegalArgumentException().isThrownBy(() -> annotation.getClassArray("types"));
}
@ClassAttributes(types = {Caffeine.class})
public static class WithClassMissingFromClasspath {
}
@Retention(RetentionPolicy.RUNTIME)
public @interface ClassAttributes {
Class<?>[] types();
}
}