1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.juneau.reflect;
18
19 import static java.lang.annotation.ElementType.*;
20 import static java.lang.annotation.RetentionPolicy.*;
21 import static org.apache.juneau.common.utils.Utils.*;
22 import static org.junit.jupiter.api.Assertions.*;
23
24 import java.lang.annotation.*;
25 import java.util.*;
26 import java.util.function.*;
27 import java.util.stream.*;
28
29 import org.apache.juneau.*;
30 import org.apache.juneau.annotation.*;
31 import org.apache.juneau.internal.*;
32 import org.junit.jupiter.api.*;
33
34
35
36
37 class ParamInfoTest extends TestBase {
38
39 @Documented
40 @Target(METHOD)
41 @Retention(RUNTIME)
42 @Inherited
43 public static @interface A {
44 String value();
45 }
46
47 @Documented
48 @Target(METHOD)
49 @Retention(RUNTIME)
50 @Inherited
51 public static @interface AX {
52 String value();
53 }
54
55 private static void check(String expected, Object o) {
56 assertEquals(expected, TO_STRING.apply(o));
57 }
58
59 private static final Function<Object,String> TO_STRING = new Function<>() {
60 @Override
61 public String apply(Object t) {
62 if (t == null)
63 return null;
64 if (t instanceof List)
65 return ((List<?>)t).stream().map(this).collect(Collectors.joining(","));
66 if (isArray(t))
67 return StreamSupport.stream(ArrayUtils.toList(t, Object.class).spliterator(), false).map(this).collect(Collectors.joining(","));
68 if (t instanceof MethodInfo)
69 return ((MethodInfo)t).getDeclaringClass().getSimpleName() + '.' + ((MethodInfo)t).getShortName();
70 if (t instanceof CA)
71 return "@CA(" + ((CA)t).value() + ")";
72 if (t instanceof DA)
73 return "@DA(" + ((DA)t).value() + ")";
74 if (t instanceof ClassInfo)
75 return ((ClassInfo)t).getSimpleName();
76 return t.toString();
77 }
78 };
79
80
81
82
83
84 static class B {
85 public B(int a, String b) {}
86 public void a1(int a, String b) {}
87 void a2(int a, String b) {}
88 }
89
90 static ClassInfo b = ClassInfo.of(B.class);
91 static ParamInfo
92 b_b_a = b.getPublicConstructor(x -> x.hasParamTypes(int.class, String.class)).getParam(0),
93 b_b_b = b.getPublicConstructor(x -> x.hasParamTypes(int.class, String.class)).getParam(1),
94 b_a1_a = b.getMethod(x -> x.hasName("a1")).getParam(0),
95 b_a1_b = b.getMethod(x -> x.hasName("a1")).getParam(1),
96 b_a2_a = b.getMethod(x -> x.hasName("a2")).getParam(0),
97 b_a2_b = b.getMethod(x -> x.hasName("a2")).getParam(1);
98
99
100 @Test void getIndex() {
101 assertEquals(0, b_b_a.getIndex());
102 assertEquals(1, b_b_b.getIndex());
103 assertEquals(0, b_a1_a.getIndex());
104 assertEquals(1, b_a1_b.getIndex());
105 assertEquals(0, b_a2_a.getIndex());
106 assertEquals(1, b_a2_b.getIndex());
107 }
108
109 @Test void getMethod() {
110 check("B.a1(int,String)", b_a1_a.getMethod());
111 check("B.a1(int,String)", b_a1_b.getMethod());
112 check("B.a2(int,String)", b_a2_a.getMethod());
113 check("B.a2(int,String)", b_a2_b.getMethod());
114 }
115
116 @Test void getMethod_onConstrutor() {
117 check(null, b_b_a.getMethod());
118 check(null, b_b_b.getMethod());
119 }
120
121 @Test void getConstructor() {
122 check("B(int,String)", b_b_a.getConstructor());
123 check("B(int,String)", b_b_b.getConstructor());
124 }
125
126 @Test void getConstructor_onMethod() {
127 check(null, b_a1_a.getConstructor());
128 check(null, b_a1_b.getConstructor());
129 check(null, b_a2_a.getConstructor());
130 check(null, b_a2_b.getConstructor());
131 }
132
133 @Test void getParameterType() {
134 check("int", b_b_a.getParameterType());
135 check("String", b_b_b.getParameterType());
136 check("int", b_a1_a.getParameterType());
137 check("String", b_a1_b.getParameterType());
138 check("int", b_a2_a.getParameterType());
139 check("String", b_a2_b.getParameterType());
140
141 }
142
143
144
145
146
147 @Target({PARAMETER,TYPE})
148 @Retention(RUNTIME)
149 public static @interface CA {
150 public String value();
151 }
152 @CA("1") public static class C1 extends C2 {}
153 @CA("2") public static class C2 implements C3, C4 {}
154 @CA("3") public interface C3 {}
155 @CA("4") public interface C4 {}
156
157 public interface CB {
158 void a1(@CA("5") C1 x);
159 void a2(@CA("5") C1 x);
160 }
161 public static class CC implements CB {
162 public CC(@CA("9") C1 x) {}
163 @Override
164 public void a1(C1 x) {}
165 @Override
166 public void a2(@CA("6") C1 x) {}
167 }
168 static ClassInfo
169 cb = ClassInfo.of(CB.class),
170 cc = ClassInfo.of(CC.class);
171 static ParamInfo
172 cc_cc = cc.getPublicConstructor(x -> x.hasParamTypes(C1.class)).getParam(0),
173 cb_a1 = cb.getMethod(x -> x.hasName("a1")).getParam(0),
174 cb_a2 = cb.getMethod(x -> x.hasName("a2")).getParam(0),
175 cc_a1 = cc.getMethod(x -> x.hasName("a1")).getParam(0),
176 cc_a2 = cc.getMethod(x -> x.hasName("a2")).getParam(0);
177
178 @Test void getDeclaredAnnotations() {
179 check("@CA(5)", declaredAnnotations(cb_a1, CA.class));
180 check("@CA(5)", declaredAnnotations(cb_a2, CA.class));
181 check("", declaredAnnotations(cc_a1, CA.class));
182 check("@CA(6)", declaredAnnotations(cc_a2, CA.class));
183 }
184
185 @Test void getDeclaredAnnotations_constructor() {
186 check("@CA(9)", declaredAnnotations(cc_cc, CA.class));
187 }
188
189 private static <T extends Annotation> List<T> declaredAnnotations(ParamInfo pi, Class<T> type) {
190 var l = new ArrayList<T>();
191 pi.forEachDeclaredAnnotation(type, x -> true, l::add);
192 return l;
193 }
194
195 @Test void getDeclaredAnnotation() {
196 check("@CA(5)", cb_a1.getDeclaredAnnotation(CA.class));
197 check("@CA(5)", cb_a2.getDeclaredAnnotation(CA.class));
198 check(null, cc_a1.getDeclaredAnnotation(CA.class));
199 check("@CA(6)", cc_a2.getDeclaredAnnotation(CA.class));
200 }
201
202 @Test void getDeclaredAnnotation_constructor() {
203 check("@CA(9)", cc_cc.getDeclaredAnnotation(CA.class));
204 }
205
206 @Test void getDeclaredAnnotation_notFound() {
207 check(null, cb_a1.getDeclaredAnnotation(DA.class));
208 }
209
210 @Test void getDeclaredAnnotation_notFound_constructor() {
211 check(null, cc_cc.getDeclaredAnnotation(DA.class));
212 }
213
214 @Test void getDeclaredAnnotation_null() {
215 check(null, cb_a1.getDeclaredAnnotation(null));
216 }
217
218 @Test void getDeclaredAnnotation_null_constructor() {
219 check(null, cc_cc.getDeclaredAnnotation(null));
220 }
221
222 @Test void getAnnotationsParentFirst() {
223 check("@CA(4),@CA(3),@CA(2),@CA(1),@CA(5)", annotations(cb_a1, CA.class));
224 check("@CA(4),@CA(3),@CA(2),@CA(1),@CA(5)", annotations(cb_a2, CA.class));
225 check("@CA(4),@CA(3),@CA(2),@CA(1),@CA(5)", annotations(cc_a1, CA.class));
226 check("@CA(4),@CA(3),@CA(2),@CA(1),@CA(5),@CA(6)", annotations(cc_a2, CA.class));
227 }
228
229 @Test void getAnnotationsParentFirst_notFound() {
230 check("", annotations(cb_a1, DA.class));
231 }
232
233 @Test void getAnnotationsParentFirst_constructor() {
234 check("@CA(4),@CA(3),@CA(2),@CA(1),@CA(9)", annotations(cc_cc, CA.class));
235 }
236
237 @Test void getAnnotationsParentFirst_notFound_constructor() {
238 check("", annotations(cc_cc, DA.class));
239 }
240
241 @Test void getAnnotation() {
242 check("@CA(5)", cb_a1.getAnnotation(CA.class));
243 check("@CA(5)", cb_a2.getAnnotation(CA.class));
244 check("@CA(5)", cc_a1.getAnnotation(CA.class));
245 check("@CA(6)", cc_a2.getAnnotation(CA.class));
246 }
247
248 @Test void getAnnotation_notFound() {
249 check(null, cb_a1.getAnnotation(DA.class));
250 }
251
252 @Test void getAnnotation_constructor() {
253 check("@CA(9)", cc_cc.getAnnotation(CA.class));
254 }
255
256 @Test void getAnnotation_notFound_constructor() {
257 check(null, cc_cc.getAnnotation(DA.class));
258 }
259
260 @Test void getAnnotation_twice() {
261 check("@CA(5)", cb_a1.getAnnotation(CA.class));
262 check("@CA(5)", cb_a1.getAnnotation(CA.class));
263 }
264
265 @Test void getAnnotation_twice_constructor() {
266 check("@CA(9)", cc_cc.getAnnotation(CA.class));
267 check("@CA(9)", cc_cc.getAnnotation(CA.class));
268 }
269
270 @Test void hasAnnotation() {
271 assertTrue(cb_a1.hasAnnotation(CA.class));
272 assertTrue(cb_a2.hasAnnotation(CA.class));
273 assertTrue(cc_a1.hasAnnotation(CA.class));
274 assertTrue(cc_a2.hasAnnotation(CA.class));
275 assertFalse(cb_a1.hasAnnotation(DA.class));
276 }
277
278 @Test void hasAnnotation_constructor() {
279 assertTrue(cc_cc.hasAnnotation(CA.class));
280 assertFalse(cc_cc.hasAnnotation(DA.class));
281 }
282
283 @Target({PARAMETER,TYPE})
284 @Retention(RUNTIME)
285 @Inherited
286 public static @interface DA {
287 public String value();
288 }
289 @DA("1") public static class D1 extends D2 {}
290 @DA("2") public static class D2 implements D3, D4 {}
291 @DA("3") public interface D3 {}
292 @DA("4") public interface D4 {}
293
294 public interface DB {
295 void a1(@DA("0") D1 x);
296 }
297 public static class DC implements DB {
298 @Override
299 public void a1(@DA("5") D1 x) {}
300 }
301
302 static ClassInfo
303 db = ClassInfo.of(DB.class),
304 dc = ClassInfo.of(DC.class);
305 static ParamInfo
306 db_a1 = db.getMethod(x -> x.hasName("a1")).getParam(0),
307 dc_a1 = dc.getMethod(x -> x.hasName("a1")).getParam(0);
308
309 @Test void getAnnotationsParentFirst_inherited() {
310 check("@DA(4),@DA(3),@DA(2),@DA(1),@DA(0)", annotations(db_a1, DA.class));
311 check("@DA(4),@DA(3),@DA(2),@DA(1),@DA(0),@DA(5)", annotations(dc_a1, DA.class));
312 }
313
314 @Test void getAnnotationsParentFirst_inherited_notFound() {
315 check("", annotations(db_a1, CA.class));
316 }
317
318 @Test void getAnnotation_inherited() {
319 check("@DA(0)", db_a1.getAnnotation(DA.class));
320 check("@DA(5)", dc_a1.getAnnotation(DA.class));
321 }
322
323 @Test void getAnnotation_inherited_notFound() {
324 check(null, db_a1.getAnnotation(CA.class));
325 }
326
327
328
329
330
331 static class E {
332 public void a1(int a, @Name("b") int b) {}
333 }
334
335 static ClassInfo e = ClassInfo.of(E.class);
336 static ParamInfo
337 e_a1_a = e.getMethod(x -> x.hasName("a1")).getParam(0),
338 e_a1_b = e.getMethod(x -> x.hasName("a1")).getParam(1);
339
340 @Test void hasName() {
341 e_a1_a.hasName();
342 assertTrue(e_a1_b.hasName());
343 }
344
345 @Test void getName() {
346 e_a1_a.getName();
347 assertEquals("b", e_a1_b.getName());
348 }
349
350 @Test void toString2() {
351 assertEquals("a1[1]", e_a1_b.toString());
352 }
353
354
355
356
357
358 private static <T extends Annotation> List<T> annotations(ParamInfo pi, Class<T> a) {
359 List<T> l = list();
360 pi.forEachAnnotation(a, x -> true, l::add);
361 return l;
362 }
363 }