Refine exception handling for type not present versus access exception

Includes TypeVariable bypass for reflection-free annotation retrieval.
Includes info log message for annotation attribute retrieval failure.

Closes gh-27182

(cherry picked from commit 70247c4a94)
This commit is contained in:
Juergen Hoeller
2024-01-06 23:02:59 +01:00
parent d074f660a1
commit dd0d26b4ba
7 changed files with 417 additions and 472 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -43,55 +43,45 @@ class AnnotationIntrospectionFailureTests {
@Test
void filteredTypeThrowsTypeNotPresentException() throws Exception {
FilteringClassLoader classLoader = new FilteringClassLoader(
getClass().getClassLoader());
Class<?> withExampleAnnotation = ClassUtils.forName(
WithExampleAnnotation.class.getName(), classLoader);
Annotation annotation = withExampleAnnotation.getAnnotations()[0];
FilteringClassLoader classLoader = new FilteringClassLoader(getClass().getClassLoader());
Class<?> withAnnotation = ClassUtils.forName(WithExampleAnnotation.class.getName(), classLoader);
Annotation annotation = withAnnotation.getAnnotations()[0];
Method method = annotation.annotationType().getMethod("value");
method.setAccessible(true);
assertThatExceptionOfType(TypeNotPresentException.class).isThrownBy(() ->
ReflectionUtils.invokeMethod(method, annotation))
.withCauseInstanceOf(ClassNotFoundException.class);
assertThatExceptionOfType(TypeNotPresentException.class)
.isThrownBy(() -> ReflectionUtils.invokeMethod(method, annotation))
.withCauseInstanceOf(ClassNotFoundException.class);
}
@Test
@SuppressWarnings("unchecked")
void filteredTypeInMetaAnnotationWhenUsingAnnotatedElementUtilsHandlesException() throws Exception {
FilteringClassLoader classLoader = new FilteringClassLoader(
getClass().getClassLoader());
Class<?> withExampleMetaAnnotation = ClassUtils.forName(
WithExampleMetaAnnotation.class.getName(), classLoader);
Class<Annotation> exampleAnnotationClass = (Class<Annotation>) ClassUtils.forName(
ExampleAnnotation.class.getName(), classLoader);
Class<Annotation> exampleMetaAnnotationClass = (Class<Annotation>) ClassUtils.forName(
ExampleMetaAnnotation.class.getName(), classLoader);
assertThat(AnnotatedElementUtils.getMergedAnnotationAttributes(
withExampleMetaAnnotation, exampleAnnotationClass)).isNull();
assertThat(AnnotatedElementUtils.getMergedAnnotationAttributes(
withExampleMetaAnnotation, exampleMetaAnnotationClass)).isNull();
assertThat(AnnotatedElementUtils.hasAnnotation(withExampleMetaAnnotation,
exampleAnnotationClass)).isFalse();
assertThat(AnnotatedElementUtils.hasAnnotation(withExampleMetaAnnotation,
exampleMetaAnnotationClass)).isFalse();
FilteringClassLoader classLoader = new FilteringClassLoader(getClass().getClassLoader());
Class<?> withAnnotation = ClassUtils.forName(WithExampleMetaAnnotation.class.getName(), classLoader);
Class<Annotation> annotationClass = (Class<Annotation>)
ClassUtils.forName(ExampleAnnotation.class.getName(), classLoader);
Class<Annotation> metaAnnotationClass = (Class<Annotation>)
ClassUtils.forName(ExampleMetaAnnotation.class.getName(), classLoader);
assertThat(AnnotatedElementUtils.getMergedAnnotationAttributes(withAnnotation, annotationClass)).isNull();
assertThat(AnnotatedElementUtils.getMergedAnnotationAttributes(withAnnotation, metaAnnotationClass)).isNull();
assertThat(AnnotatedElementUtils.hasAnnotation(withAnnotation, annotationClass)).isFalse();
assertThat(AnnotatedElementUtils.hasAnnotation(withAnnotation, metaAnnotationClass)).isFalse();
}
@Test
@SuppressWarnings("unchecked")
void filteredTypeInMetaAnnotationWhenUsingMergedAnnotationsHandlesException() throws Exception {
FilteringClassLoader classLoader = new FilteringClassLoader(
getClass().getClassLoader());
Class<?> withExampleMetaAnnotation = ClassUtils.forName(
WithExampleMetaAnnotation.class.getName(), classLoader);
Class<Annotation> exampleAnnotationClass = (Class<Annotation>) ClassUtils.forName(
ExampleAnnotation.class.getName(), classLoader);
Class<Annotation> exampleMetaAnnotationClass = (Class<Annotation>) ClassUtils.forName(
ExampleMetaAnnotation.class.getName(), classLoader);
MergedAnnotations annotations = MergedAnnotations.from(withExampleMetaAnnotation);
assertThat(annotations.get(exampleAnnotationClass).isPresent()).isFalse();
assertThat(annotations.get(exampleMetaAnnotationClass).isPresent()).isFalse();
assertThat(annotations.isPresent(exampleMetaAnnotationClass)).isFalse();
assertThat(annotations.isPresent(exampleAnnotationClass)).isFalse();
FilteringClassLoader classLoader = new FilteringClassLoader(getClass().getClassLoader());
Class<?> withAnnotation = ClassUtils.forName(WithExampleMetaAnnotation.class.getName(), classLoader);
Class<Annotation> annotationClass = (Class<Annotation>)
ClassUtils.forName(ExampleAnnotation.class.getName(), classLoader);
Class<Annotation> metaAnnotationClass = (Class<Annotation>)
ClassUtils.forName(ExampleMetaAnnotation.class.getName(), classLoader);
MergedAnnotations annotations = MergedAnnotations.from(withAnnotation);
assertThat(annotations.get(annotationClass).isPresent()).isFalse();
assertThat(annotations.get(metaAnnotationClass).isPresent()).isFalse();
assertThat(annotations.isPresent(metaAnnotationClass)).isFalse();
assertThat(annotations.isPresent(annotationClass)).isFalse();
}
@@ -103,17 +93,16 @@ class AnnotationIntrospectionFailureTests {
@Override
protected boolean isEligibleForOverriding(String className) {
return className.startsWith(
AnnotationIntrospectionFailureTests.class.getName());
return className.startsWith(AnnotationIntrospectionFailureTests.class.getName()) ||
className.startsWith("jdk.internal");
}
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
if (name.startsWith(AnnotationIntrospectionFailureTests.class.getName()) &&
name.contains("Filtered")) {
protected Class<?> loadClassForOverriding(String name) throws ClassNotFoundException {
if (name.contains("Filtered") || name.startsWith("jdk.internal")) {
throw new ClassNotFoundException(name);
}
return super.loadClass(name, resolve);
return super.loadClassForOverriding(name);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -112,7 +112,7 @@ class AttributeMethodsTests {
ClassValue annotation = mockAnnotation(ClassValue.class);
given(annotation.value()).willThrow(TypeNotPresentException.class);
AttributeMethods attributes = AttributeMethods.forAnnotationType(annotation.annotationType());
assertThat(attributes.isValid(annotation)).isFalse();
assertThat(attributes.canLoad(annotation)).isFalse();
}
@Test
@@ -121,7 +121,7 @@ class AttributeMethodsTests {
ClassValue annotation = mock();
given(annotation.value()).willReturn((Class) InputStream.class);
AttributeMethods attributes = AttributeMethods.forAnnotationType(annotation.annotationType());
assertThat(attributes.isValid(annotation)).isTrue();
assertThat(attributes.canLoad(annotation)).isTrue();
}
@Test