Skip to content

Commit fdacda8

Browse files
philwebbjhoeller
authored andcommitted
Add AnnotationIntrospectionFailureTests
Add a new test class to help cover annotation introspection failure handling. These tests were previously missing and are important to ensure that annotation util code changes don't introduce regressions. See gh-21697
1 parent 8ef609a commit fdacda8

File tree

1 file changed

+141
-0
lines changed

1 file changed

+141
-0
lines changed
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/*
2+
* Copyright 2002-2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.core.annotation;
18+
19+
import java.lang.annotation.Annotation;
20+
import java.lang.annotation.Retention;
21+
import java.lang.annotation.RetentionPolicy;
22+
import java.lang.reflect.Method;
23+
24+
import org.junit.Test;
25+
26+
import org.springframework.core.OverridingClassLoader;
27+
import org.springframework.util.ClassUtils;
28+
import org.springframework.util.ReflectionUtils;
29+
30+
import static org.assertj.core.api.Assertions.*;
31+
32+
/**
33+
* Tests that trigger annotation introspection failures and ensure that they are
34+
* dealt with correctly.
35+
*
36+
* @author Phillip Webb
37+
* @since 5.2
38+
* @see AnnotationUtils
39+
* @see AnnotatedElementUtils
40+
*/
41+
public class AnnotationIntrospectionFailureTests {
42+
43+
@Test
44+
public void filteredTypeThrowsTypeNotPresentException() throws Exception {
45+
FilteringClassLoader classLoader = new FilteringClassLoader(
46+
getClass().getClassLoader());
47+
Class<?> withExampleAnnotation = ClassUtils.forName(
48+
WithExampleAnnotation.class.getName(), classLoader);
49+
Annotation annotation = withExampleAnnotation.getAnnotations()[0];
50+
Method method = annotation.annotationType().getMethod("value");
51+
method.setAccessible(true);
52+
assertThatExceptionOfType(TypeNotPresentException.class).isThrownBy(() -> {
53+
ReflectionUtils.invokeMethod(method, annotation);
54+
}).withCauseInstanceOf(ClassNotFoundException.class);
55+
}
56+
57+
@Test
58+
@SuppressWarnings("unchecked")
59+
public void filteredTypeInMetaAnnotationWhenUsingAnnotatedElementUtilsHandlesException() throws Exception {
60+
FilteringClassLoader classLoader = new FilteringClassLoader(
61+
getClass().getClassLoader());
62+
Class<?> withExampleMetaAnnotation = ClassUtils.forName(
63+
WithExampleMetaAnnotation.class.getName(), classLoader);
64+
Class<Annotation> exampleAnnotationClass = (Class<Annotation>) ClassUtils.forName(
65+
ExampleAnnotation.class.getName(), classLoader);
66+
Class<Annotation> exampleMetaAnnotationClass = (Class<Annotation>) ClassUtils.forName(
67+
ExampleMetaAnnotation.class.getName(), classLoader);
68+
assertThat(AnnotatedElementUtils.getMergedAnnotationAttributes(
69+
withExampleMetaAnnotation, exampleAnnotationClass)).isNull();
70+
assertThat(AnnotatedElementUtils.getMergedAnnotationAttributes(
71+
withExampleMetaAnnotation,
72+
exampleMetaAnnotationClass)).isNull();
73+
// Ideally hasAnnotation should return false, however, it currently
74+
// detects annotations that might ultimately not load
75+
assertThat(AnnotatedElementUtils.hasAnnotation(withExampleMetaAnnotation,
76+
exampleAnnotationClass)).isTrue();
77+
assertThat(AnnotatedElementUtils.hasAnnotation(withExampleMetaAnnotation,
78+
exampleMetaAnnotationClass)).isTrue();
79+
}
80+
81+
82+
static class FilteringClassLoader extends OverridingClassLoader {
83+
84+
85+
FilteringClassLoader(ClassLoader parent) {
86+
super(parent);
87+
}
88+
89+
90+
@Override
91+
protected boolean isEligibleForOverriding(String className) {
92+
return className.startsWith(
93+
AnnotationIntrospectionFailureTests.class.getName());
94+
}
95+
96+
@Override
97+
protected Class<?> loadClass(String name, boolean resolve)
98+
throws ClassNotFoundException {
99+
if (name.startsWith(AnnotationIntrospectionFailureTests.class.getName())
100+
&& name.contains("Filtered")) {
101+
throw new ClassNotFoundException(name);
102+
}
103+
return super.loadClass(name, resolve);
104+
}
105+
106+
}
107+
108+
static class FilteredType {
109+
110+
}
111+
112+
@Retention(RetentionPolicy.RUNTIME)
113+
static @interface ExampleAnnotation {
114+
115+
Class<?> value() default Void.class;
116+
117+
}
118+
119+
@ExampleAnnotation(FilteredType.class)
120+
static class WithExampleAnnotation {
121+
122+
}
123+
124+
@Retention(RetentionPolicy.RUNTIME)
125+
@ExampleAnnotation
126+
static @interface ExampleMetaAnnotation {
127+
128+
@AliasFor(annotation = ExampleAnnotation.class, attribute = "value")
129+
Class<?> example1() default Void.class;
130+
131+
@AliasFor(annotation = ExampleAnnotation.class, attribute = "value")
132+
Class<?> example2() default Void.class;
133+
134+
}
135+
136+
@ExampleMetaAnnotation(example1 = FilteredType.class)
137+
static class WithExampleMetaAnnotation {
138+
139+
}
140+
141+
}

0 commit comments

Comments
 (0)