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 b7b7bdf1ddc..e7937c815cd 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
@@ -450,7 +450,12 @@ final class TypeMappedAnnotation extends AbstractMergedAnn
value = clazz.getName();
}
else if (value instanceof String str && type == Class.class) {
- value = ClassUtils.resolveClassName(str, getClassLoader());
+ try {
+ value = ClassUtils.forName(str, getClassLoader());
+ }
+ catch (ClassNotFoundException | LinkageError ex) {
+ throw new TypeNotPresentException(str, ex);
+ }
}
else if (value instanceof Class>[] classes && type == String[].class) {
String[] names = new String[classes.length];
@@ -461,8 +466,14 @@ final class TypeMappedAnnotation extends AbstractMergedAnn
}
else if (value instanceof String[] names && type == Class[].class) {
Class>[] classes = new Class>[names.length];
+ ClassLoader classLoader = getClassLoader();
for (int i = 0; i < names.length; i++) {
- classes[i] = ClassUtils.resolveClassName(names[i], getClassLoader());
+ try {
+ classes[i] = ClassUtils.forName(names[i], classLoader);
+ }
+ catch (ClassNotFoundException | LinkageError ex) {
+ throw new TypeNotPresentException(names[i], ex);
+ }
}
value = classes;
}
diff --git a/spring-core/src/main/java/org/springframework/core/type/classreading/MergedAnnotationReadingVisitor.java b/spring-core/src/main/java/org/springframework/core/type/classreading/MergedAnnotationReadingVisitor.java
index 0af13e6d002..8d2a82cf406 100644
--- a/spring-core/src/main/java/org/springframework/core/type/classreading/MergedAnnotationReadingVisitor.java
+++ b/spring-core/src/main/java/org/springframework/core/type/classreading/MergedAnnotationReadingVisitor.java
@@ -101,7 +101,13 @@ class MergedAnnotationReadingVisitor extends AnnotationVis
@SuppressWarnings("unchecked")
public > void visitEnum(String descriptor, String value, Consumer consumer) {
String className = Type.getType(descriptor).getClassName();
- Class type = (Class) ClassUtils.resolveClassName(className, this.classLoader);
+ Class type = null;
+ try {
+ type = (Class) ClassUtils.forName(className, this.classLoader);
+ }
+ catch (ClassNotFoundException | LinkageError ex) {
+ throw new TypeNotPresentException(className, ex);
+ }
consumer.accept(Enum.valueOf(type, value));
}
@@ -113,7 +119,13 @@ class MergedAnnotationReadingVisitor extends AnnotationVis
if (AnnotationFilter.PLAIN.matches(className)) {
return null;
}
- Class type = (Class) ClassUtils.resolveClassName(className, this.classLoader);
+ Class type = null;
+ try {
+ type = (Class) ClassUtils.forName(className, this.classLoader);
+ }
+ catch (ClassNotFoundException | LinkageError ex) {
+ throw new TypeNotPresentException(className, ex);
+ }
return new MergedAnnotationReadingVisitor<>(this.classLoader, this.source, type, consumer);
}
diff --git a/spring-core/src/main/java24/org/springframework/core/type/classreading/ClassFileAnnotationDelegate.java b/spring-core/src/main/java24/org/springframework/core/type/classreading/ClassFileAnnotationDelegate.java
index 810636236da..45934d608ee 100644
--- a/spring-core/src/main/java24/org/springframework/core/type/classreading/ClassFileAnnotationDelegate.java
+++ b/spring-core/src/main/java24/org/springframework/core/type/classreading/ClassFileAnnotationDelegate.java
@@ -139,7 +139,12 @@ abstract class ClassFileAnnotationDelegate {
private static Class> loadEnumClass(AnnotationValue.OfEnum enumValue, @Nullable ClassLoader classLoader) {
String className = ClassFileAnnotationMetadata.resolveTypeName(enumValue.classSymbol());
- return ClassUtils.resolveClassName(className, classLoader);
+ try {
+ return ClassUtils.forName(className, classLoader);
+ }
+ catch (ClassNotFoundException | LinkageError ex) {
+ throw new TypeNotPresentException(className, ex);
+ }
}
private static Class> resolveArrayElementType(List values, @Nullable ClassLoader classLoader) {
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 e2d7f4f049c..b46fd990af7 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
@@ -31,6 +31,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.core.annotation.MergedAnnotation.Adapt;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.InstanceOfAssertFactories.throwable;
@@ -143,16 +144,16 @@ class TypeMappedAnnotationTests {
Map.of(attributeName, "com.example.DoesNotExist"));
// 0) Sanity check MergedAnnotation.getClass() behavior.
- assertThatIllegalArgumentException()
+ assertThatExceptionOfType(TypeNotPresentException.class)
.isThrownBy(() -> mergedAnnotation.getClass(attributeName))
- .withMessage("Could not find class [com.example.DoesNotExist]")
- .withCauseInstanceOf(ClassNotFoundException.class);
+ .withMessageContaining("com.example.DoesNotExist")
+ .withCauseExactlyInstanceOf(ClassNotFoundException.class);
var map = mergedAnnotation.asMap(Adapt.values(false, true));
// 1) Attribute should be present, even though its value is an exception.
assertThat(map).containsKey(attributeName);
- assertThat(map.get(attributeName)).asInstanceOf(throwable(IllegalArgumentException.class))
+ assertThat(map.get(attributeName)).asInstanceOf(throwable(TypeNotPresentException.class))
.hasMessageContaining("com.example.DoesNotExist");
}
@@ -163,16 +164,16 @@ class TypeMappedAnnotationTests {
Map.of(attributeName, new String[] { "com.example.DoesNotExist" }));
// 0) Sanity check MergedAnnotation.getClassArray() behavior.
- assertThatIllegalArgumentException()
+ assertThatExceptionOfType(TypeNotPresentException.class)
.isThrownBy(() -> mergedAnnotation.getClassArray(attributeName))
- .withMessage("Could not find class [com.example.DoesNotExist]")
+ .withMessageContaining("com.example.DoesNotExist")
.withCauseExactlyInstanceOf(ClassNotFoundException.class);
var map = mergedAnnotation.asMap(Adapt.values(false, true));
// 1) Attribute should be present, even though its value is an exception.
assertThat(map).containsKey(attributeName);
- assertThat(map.get(attributeName)).asInstanceOf(throwable(IllegalArgumentException.class))
+ assertThat(map.get(attributeName)).asInstanceOf(throwable(TypeNotPresentException.class))
.hasMessageContaining("com.example.DoesNotExist");
}
}
@@ -188,16 +189,16 @@ class TypeMappedAnnotationTests {
Map.of(attributeName, "com.example.DoesNotExist"));
// 0) Sanity check MergedAnnotation.getClass() behavior.
- assertThatIllegalArgumentException()
+ assertThatExceptionOfType(TypeNotPresentException.class)
.isThrownBy(() -> mergedAnnotation.getClass(attributeName))
- .withMessage("Could not find class [com.example.DoesNotExist]")
- .withCauseInstanceOf(ClassNotFoundException.class);
+ .withMessageContaining("com.example.DoesNotExist")
+ .withCauseExactlyInstanceOf(ClassNotFoundException.class);
var attributes = mergedAnnotation.asAnnotationAttributes(Adapt.values(false, true));
// 1) Attribute should be present, even though its value is an exception.
assertThat(attributes).containsKey(attributeName);
- assertThat(attributes.get(attributeName)).asInstanceOf(throwable(IllegalArgumentException.class))
+ assertThat(attributes.get(attributeName)).asInstanceOf(throwable(TypeNotPresentException.class))
.hasMessageContaining("com.example.DoesNotExist");
// 2) Accessing the attribute via AnnotationAttributes.getClassArray() should throw an
@@ -213,16 +214,16 @@ class TypeMappedAnnotationTests {
Map.of(attributeName, new String[] { "com.example.DoesNotExist" }));
// 0) Sanity check MergedAnnotation.getClassArray() behavior.
- assertThatIllegalArgumentException()
+ assertThatExceptionOfType(TypeNotPresentException.class)
.isThrownBy(() -> mergedAnnotation.getClassArray(attributeName))
- .withMessage("Could not find class [com.example.DoesNotExist]")
- .withCauseInstanceOf(ClassNotFoundException.class);
+ .withMessageContaining("com.example.DoesNotExist")
+ .withCauseExactlyInstanceOf(ClassNotFoundException.class);
var attributes = mergedAnnotation.asAnnotationAttributes(Adapt.values(false, true));
// 1) Attribute should be present, even though its value is an exception.
assertThat(attributes).containsKey(attributeName);
- assertThat(attributes.get(attributeName)).asInstanceOf(throwable(IllegalArgumentException.class))
+ assertThat(attributes.get(attributeName)).asInstanceOf(throwable(TypeNotPresentException.class))
.hasMessageContaining("com.example.DoesNotExist");
// 2) Accessing the attribute via AnnotationAttributes.getClassArray() should throw an
@@ -236,9 +237,9 @@ class TypeMappedAnnotationTests {
.isThrownBy(throwingCallable)
.withMessageMatching("""
Attribute '%s' for annotation \\[.+?\\] was not resolvable \
- due to exception \\[.+?IllegalArgumentException.+?\\]""".formatted(attributeName))
+ due to exception \\[.+?TypeNotPresentException.+?\\]""".formatted(attributeName))
.havingCause()
- .isExactlyInstanceOf(IllegalArgumentException.class)
+ .isExactlyInstanceOf(TypeNotPresentException.class)
.withMessageContaining("com.example.DoesNotExist")
.havingCause()
.isExactlyInstanceOf(ClassNotFoundException.class)
diff --git a/spring-core/src/test/java/org/springframework/core/type/classreading/DefaultAnnotationMetadataTests.java b/spring-core/src/test/java/org/springframework/core/type/classreading/DefaultAnnotationMetadataTests.java
index 58f64bb3da5..025c7ebf2df 100644
--- a/spring-core/src/test/java/org/springframework/core/type/classreading/DefaultAnnotationMetadataTests.java
+++ b/spring-core/src/test/java/org/springframework/core/type/classreading/DefaultAnnotationMetadataTests.java
@@ -27,7 +27,7 @@ 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;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* Tests for {@link SimpleAnnotationMetadata} and
@@ -59,7 +59,9 @@ class DefaultAnnotationMetadataTests extends AbstractAnnotationMetadataTests {
.getAnnotations()
.get(ClassAttributes.class);
assertThat(mergedAnnotation.getStringArray("types")).contains("javax.annotation.meta.When");
- assertThatIllegalArgumentException().isThrownBy(() -> mergedAnnotation.getClassArray("types"));
+ assertThatExceptionOfType(TypeNotPresentException.class)
+ .isThrownBy(() -> mergedAnnotation.getClassArray("types"))
+ .withMessageContaining("javax.annotation.meta.When");
}
diff --git a/spring-core/src/test/java/org/springframework/core/type/classreading/SimpleAnnotationMetadataTests.java b/spring-core/src/test/java/org/springframework/core/type/classreading/SimpleAnnotationMetadataTests.java
index 28432205943..3b60299835c 100644
--- a/spring-core/src/test/java/org/springframework/core/type/classreading/SimpleAnnotationMetadataTests.java
+++ b/spring-core/src/test/java/org/springframework/core/type/classreading/SimpleAnnotationMetadataTests.java
@@ -27,7 +27,7 @@ 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;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* Tests for {@link SimpleAnnotationMetadata} and
@@ -58,7 +58,9 @@ class SimpleAnnotationMetadataTests extends AbstractAnnotationMetadataTests {
.getAnnotations()
.get(ClassAttributes.class);
assertThat(mergedAnnotation.getStringArray("types")).contains("javax.annotation.meta.When");
- assertThatIllegalArgumentException().isThrownBy(() -> mergedAnnotation.getClassArray("types"));
+ assertThatExceptionOfType(TypeNotPresentException.class)
+ .isThrownBy(() -> mergedAnnotation.getClassArray("types"))
+ .withMessageContaining("javax.annotation.meta.When");
}