1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.google.common.reflect;
18
19 import com.google.common.collect.ImmutableList;
20 import com.google.common.collect.Iterables;
21 import com.google.common.testing.EqualsTester;
22 import com.google.common.testing.NullPointerTester;
23
24 import junit.framework.TestCase;
25
26 import java.lang.annotation.Retention;
27 import java.lang.annotation.RetentionPolicy;
28 import java.lang.reflect.Constructor;
29 import java.lang.reflect.Method;
30 import java.lang.reflect.ParameterizedType;
31 import java.lang.reflect.TypeVariable;
32 import java.util.Collections;
33
34 import javax.annotation.Nullable;
35
36
37
38
39
40
41 public class InvokableTest extends TestCase {
42
43 public void testConstructor_returnType() throws Exception {
44 assertEquals(Prepender.class,
45 Prepender.constructor().getReturnType().getType());
46 }
47
48 private static class WithConstructorAndTypeParameter<T> {
49 @SuppressWarnings("unused")
50 <X> WithConstructorAndTypeParameter() {}
51 }
52
53 public void testConstructor_returnType_hasTypeParameter() throws Exception {
54 @SuppressWarnings("rawtypes")
55 Class<WithConstructorAndTypeParameter> type = WithConstructorAndTypeParameter.class;
56 @SuppressWarnings("rawtypes")
57 Constructor<WithConstructorAndTypeParameter> constructor = type.getDeclaredConstructor();
58 Invokable<?, ?> factory = Invokable.from(constructor);
59 assertEquals(2, factory.getTypeParameters().length);
60 assertEquals(type.getTypeParameters()[0], factory.getTypeParameters()[0]);
61 assertEquals(constructor.getTypeParameters()[0], factory.getTypeParameters()[1]);
62 ParameterizedType returnType = (ParameterizedType) factory.getReturnType().getType();
63 assertEquals(type, returnType.getRawType());
64 assertEquals(ImmutableList.copyOf(type.getTypeParameters()),
65 ImmutableList.copyOf(returnType.getActualTypeArguments()));
66 }
67
68 public void testConstructor_exceptionTypes() throws Exception {
69 assertEquals(ImmutableList.of(TypeToken.of(NullPointerException.class)),
70 Prepender.constructor(String.class, int.class).getExceptionTypes());
71 }
72
73 public void testConstructor_typeParameters() throws Exception {
74 TypeVariable<?>[] variables =
75 Prepender.constructor().getTypeParameters();
76 assertEquals(1, variables.length);
77 assertEquals("A", variables[0].getName());
78 }
79
80 public void testConstructor_parameters() throws Exception {
81 Invokable<?, Prepender> delegate = Prepender.constructor(String.class, int.class);
82 ImmutableList<Parameter> parameters = delegate.getParameters();
83 assertEquals(2, parameters.size());
84 assertEquals(String.class, parameters.get(0).getType().getType());
85 assertTrue(parameters.get(0).isAnnotationPresent(NotBlank.class));
86 assertEquals(int.class, parameters.get(1).getType().getType());
87 assertFalse(parameters.get(1).isAnnotationPresent(NotBlank.class));
88 new EqualsTester()
89 .addEqualityGroup(parameters.get(0))
90 .addEqualityGroup(parameters.get(1))
91 .testEquals();
92 }
93
94 public void testConstructor_call() throws Exception {
95 Invokable<?, Prepender> delegate = Prepender.constructor(String.class, int.class);
96 Prepender prepender = delegate.invoke(null, "a", 1);
97 assertEquals("a", prepender.prefix);
98 assertEquals(1, prepender.times);
99 }
100
101 public void testConstructor_returning() throws Exception {
102 Invokable<?, Prepender> delegate = Prepender.constructor(String.class, int.class)
103 .returning(Prepender.class);
104 Prepender prepender = delegate.invoke(null, "a", 1);
105 assertEquals("a", prepender.prefix);
106 assertEquals(1, prepender.times);
107 }
108
109 public void testConstructor_invalidReturning() throws Exception {
110 Invokable<?, Prepender> delegate = Prepender.constructor(String.class, int.class);
111 try {
112 delegate.returning(SubPrepender.class);
113 fail();
114 } catch (IllegalArgumentException expected) {}
115 }
116
117 public void testStaticMethod_returnType() throws Exception {
118 Invokable<?, ?> delegate = Prepender.method("prepend", String.class, Iterable.class);
119 assertEquals(new TypeToken<Iterable<String>>() {}, delegate.getReturnType());
120 }
121
122 public void testStaticMethod_exceptionTypes() throws Exception {
123 Invokable<?, ?> delegate = Prepender.method("prepend", String.class, Iterable.class);
124 assertEquals(ImmutableList.of(), delegate.getExceptionTypes());
125 }
126
127 public void testStaticMethod_typeParameters() throws Exception {
128 Invokable<?, ?> delegate = Prepender.method("prepend", String.class, Iterable.class);
129 TypeVariable<?>[] variables = delegate.getTypeParameters();
130 assertEquals(1, variables.length);
131 assertEquals("T", variables[0].getName());
132 }
133
134 public void testStaticMethod_parameters() throws Exception {
135 Invokable<?, ?> delegate = Prepender.method("prepend", String.class, Iterable.class);
136 ImmutableList<Parameter> parameters = delegate.getParameters();
137 assertEquals(2, parameters.size());
138 assertEquals(String.class, parameters.get(0).getType().getType());
139 assertTrue(parameters.get(0).isAnnotationPresent(NotBlank.class));
140 assertEquals(new TypeToken<Iterable<String>>() {}, parameters.get(1).getType());
141 assertFalse(parameters.get(1).isAnnotationPresent(NotBlank.class));
142 new EqualsTester()
143 .addEqualityGroup(parameters.get(0))
144 .addEqualityGroup(parameters.get(1))
145 .testEquals();
146 }
147
148 public void testStaticMethod_call() throws Exception {
149 Invokable<?, ?> delegate = Prepender.method("prepend", String.class, Iterable.class);
150 @SuppressWarnings("unchecked")
151 Iterable<String> result = (Iterable<String>)
152 delegate.invoke(null, "a", ImmutableList.of("b", "c"));
153 assertEquals(ImmutableList.of("a", "b", "c"), ImmutableList.copyOf(result));
154 }
155
156 public void testStaticMethod_returning() throws Exception {
157 Invokable<?, Iterable<String>> delegate = Prepender.method(
158 "prepend", String.class, Iterable.class)
159 .returning(new TypeToken<Iterable<String>>() {});
160 assertEquals(new TypeToken<Iterable<String>>() {}, delegate.getReturnType());
161 Iterable<String> result = delegate.invoke(null, "a", ImmutableList.of("b", "c"));
162 assertEquals(ImmutableList.of("a", "b", "c"), ImmutableList.copyOf(result));
163 }
164
165 public void testStaticMethod_returningRawType() throws Exception {
166 @SuppressWarnings("rawtypes")
167 Invokable<?, Iterable> delegate = Prepender.method(
168 "prepend", String.class, Iterable.class)
169 .returning(Iterable.class);
170 assertEquals(new TypeToken<Iterable<String>>() {}, delegate.getReturnType());
171 @SuppressWarnings("unchecked")
172 Iterable<String> result = delegate.invoke(null, "a", ImmutableList.of("b", "c"));
173 assertEquals(ImmutableList.of("a", "b", "c"), ImmutableList.copyOf(result));
174 }
175
176 public void testStaticMethod_invalidReturning() throws Exception {
177 Invokable<?, Object> delegate = Prepender.method("prepend", String.class, Iterable.class);
178 try {
179 delegate.returning(new TypeToken<Iterable<Integer>>() {});
180 fail();
181 } catch (IllegalArgumentException expected) {}
182 }
183
184 public void testInstanceMethod_returnType() throws Exception {
185 Invokable<?, ?> delegate = Prepender.method("prepend", Iterable.class);
186 assertEquals(new TypeToken<Iterable<String>>() {}, delegate.getReturnType());
187 }
188
189 public void testInstanceMethod_exceptionTypes() throws Exception {
190 Invokable<?, ?> delegate = Prepender.method("prepend", Iterable.class);
191 assertEquals(
192 ImmutableList.of(
193 TypeToken.of(IllegalArgumentException.class),
194 TypeToken.of(NullPointerException.class)),
195 delegate.getExceptionTypes());
196 }
197
198 public void testInstanceMethod_typeParameters() throws Exception {
199 Invokable<?, ?> delegate = Prepender.method("prepend", Iterable.class);
200 assertEquals(0, delegate.getTypeParameters().length);
201 }
202
203 public void testInstanceMethod_parameters() throws Exception {
204 Invokable<?, ?> delegate = Prepender.method("prepend", Iterable.class);
205 ImmutableList<Parameter> parameters = delegate.getParameters();
206 assertEquals(1, parameters.size());
207 assertEquals(new TypeToken<Iterable<String>>() {}, parameters.get(0).getType());
208 assertEquals(0, parameters.get(0).getAnnotations().length);
209 new EqualsTester()
210 .addEqualityGroup(parameters.get(0))
211 .testEquals();
212 }
213
214 public void testInstanceMethod_call() throws Exception {
215 Invokable<Prepender, ?> delegate = Prepender.method("prepend", Iterable.class);
216 @SuppressWarnings("unchecked")
217 Iterable<String> result = (Iterable<String>)
218 delegate.invoke(new Prepender("a", 2), ImmutableList.of("b", "c"));
219 assertEquals(ImmutableList.of("a", "a", "b", "c"), ImmutableList.copyOf(result));
220 }
221
222 public void testInstanceMethod_returning() throws Exception {
223 Invokable<Prepender, Iterable<String>> delegate = Prepender.method(
224 "prepend", Iterable.class)
225 .returning(new TypeToken<Iterable<String>>() {});
226 assertEquals(new TypeToken<Iterable<String>>() {}, delegate.getReturnType());
227 Iterable<String> result = delegate.invoke(new Prepender("a", 2), ImmutableList.of("b", "c"));
228 assertEquals(ImmutableList.of("a", "a", "b", "c"), ImmutableList.copyOf(result));
229 }
230
231 public void testInstanceMethod_returningRawType() throws Exception {
232 @SuppressWarnings("rawtypes")
233 Invokable<Prepender, Iterable> delegate = Prepender.method("prepend", Iterable.class)
234 .returning(Iterable.class);
235 assertEquals(new TypeToken<Iterable<String>>() {}, delegate.getReturnType());
236 @SuppressWarnings("unchecked")
237 Iterable<String> result = delegate.invoke(
238 new Prepender("a", 2), ImmutableList.of("b", "c"));
239 assertEquals(ImmutableList.of("a", "a", "b", "c"), ImmutableList.copyOf(result));
240 }
241
242 public void testInstanceMethod_invalidReturning() throws Exception {
243 Invokable<?, Object> delegate = Prepender.method("prepend", Iterable.class);
244 try {
245 delegate.returning(new TypeToken<Iterable<Integer>>() {});
246 fail();
247 } catch (IllegalArgumentException expected) {}
248 }
249
250 public void testPrivateInstanceMethod_isOverridable() throws Exception {
251 Invokable<?, ?> delegate = Prepender.method("privateMethod");
252 assertTrue(delegate.isPrivate());
253 assertFalse(delegate.isOverridable());
254 assertFalse(delegate.isVarArgs());
255 }
256
257 public void testPrivateFinalInstanceMethod_isOverridable() throws Exception {
258 Invokable<?, ?> delegate = Prepender.method("privateFinalMethod");
259 assertTrue(delegate.isPrivate());
260 assertTrue(delegate.isFinal());
261 assertFalse(delegate.isOverridable());
262 assertFalse(delegate.isVarArgs());
263 }
264
265 public void testStaticMethod_isOverridable() throws Exception {
266 Invokable<?, ?> delegate = Prepender.method("staticMethod");
267 assertTrue(delegate.isStatic());
268 assertFalse(delegate.isOverridable());
269 assertFalse(delegate.isVarArgs());
270 }
271
272 public void testStaticFinalMethod_isFinal() throws Exception {
273 Invokable<?, ?> delegate = Prepender.method("staticFinalMethod");
274 assertTrue(delegate.isStatic());
275 assertTrue(delegate.isFinal());
276 assertFalse(delegate.isOverridable());
277 assertFalse(delegate.isVarArgs());
278 }
279
280 static class Foo {}
281
282 public void testConstructor_isOverridablel() throws Exception {
283 Invokable<?, ?> delegate = Invokable.from(Foo.class.getDeclaredConstructor());
284 assertFalse(delegate.isOverridable());
285 assertFalse(delegate.isVarArgs());
286 }
287
288 public void testMethod_isVarArgs() throws Exception {
289 Invokable<?, ?> delegate = Prepender.method("privateVarArgsMethod", String[].class);
290 assertTrue(delegate.isVarArgs());
291 }
292
293 public void testConstructor_isVarArgs() throws Exception {
294 Invokable<?, ?> delegate = Prepender.constructor(String[].class);
295 assertTrue(delegate.isVarArgs());
296 }
297
298 public void testGetOwnerType_constructor() throws Exception {
299 Invokable<String, String> invokable = Invokable.from(String.class.getConstructor());
300 assertEquals(TypeToken.of(String.class), invokable.getOwnerType());
301 }
302
303 public void testGetOwnerType_method() throws Exception {
304 Invokable<?, ?> invokable = Invokable.from(String.class.getMethod("length"));
305 assertEquals(TypeToken.of(String.class), invokable.getOwnerType());
306 }
307
308 private static final class FinalClass {
309 @SuppressWarnings("unused")
310 void notFinalMethod() {}
311 }
312
313 public void testNonFinalMethodInFinalClass_isOverridable() throws Exception {
314 Invokable<?, ?> delegate = Invokable.from(
315 FinalClass.class.getDeclaredMethod("notFinalMethod"));
316 assertFalse(delegate.isOverridable());
317 assertFalse(delegate.isVarArgs());
318 }
319
320 private class InnerWithDefaultConstructor {
321 class NestedInner {}
322 }
323
324 public void testInnerClassDefaultConstructor() {
325 Constructor<?> constructor =
326 InnerWithDefaultConstructor.class.getDeclaredConstructors() [0];
327 assertEquals(0, Invokable.from(constructor).getParameters().size());
328 }
329
330 public void testNestedInnerClassDefaultConstructor() {
331 Constructor<?> constructor =
332 InnerWithDefaultConstructor.NestedInner.class.getDeclaredConstructors() [0];
333 assertEquals(0, Invokable.from(constructor).getParameters().size());
334 }
335
336 private class InnerWithOneParameterConstructor {
337 @SuppressWarnings("unused")
338 public InnerWithOneParameterConstructor(String s) {}
339 }
340
341 public void testInnerClassWithOneParameterConstructor() {
342 Constructor<?> constructor =
343 InnerWithOneParameterConstructor.class.getDeclaredConstructors()[0];
344 Invokable<?, ?> invokable = Invokable.from(constructor);
345 assertEquals(1, invokable.getParameters().size());
346 assertEquals(TypeToken.of(String.class), invokable.getParameters().get(0).getType());
347 }
348
349 private class InnerWithAnnotatedConstructorParameter {
350 @SuppressWarnings("unused")
351 InnerWithAnnotatedConstructorParameter(@Nullable String s) {}
352 }
353
354 public void testInnerClassWithAnnotatedConstructorParameter() {
355 Constructor<?> constructor =
356 InnerWithAnnotatedConstructorParameter.class.getDeclaredConstructors() [0];
357 Invokable<?, ?> invokable = Invokable.from(constructor);
358 assertEquals(1, invokable.getParameters().size());
359 assertEquals(TypeToken.of(String.class), invokable.getParameters().get(0).getType());
360 }
361
362 private class InnerWithGenericConstructorParameter {
363 @SuppressWarnings("unused")
364 InnerWithGenericConstructorParameter(Iterable<String> it, String s) {}
365 }
366
367 public void testInnerClassWithGenericConstructorParameter() {
368 Constructor<?> constructor =
369 InnerWithGenericConstructorParameter.class.getDeclaredConstructors() [0];
370 Invokable<?, ?> invokable = Invokable.from(constructor);
371 assertEquals(2, invokable.getParameters().size());
372 assertEquals(new TypeToken<Iterable<String>>() {},
373 invokable.getParameters().get(0).getType());
374 assertEquals(TypeToken.of(String.class),
375 invokable.getParameters().get(1).getType());
376 }
377
378 public void testAnonymousClassDefaultConstructor() {
379 final int i = 1;
380 final String s = "hello world";
381 Class<?> anonymous = new Runnable() {
382 @Override public void run() {
383 System.out.println(s + i);
384 }
385 }.getClass();
386 Constructor<?> constructor = anonymous.getDeclaredConstructors() [0];
387 assertEquals(0, Invokable.from(constructor).getParameters().size());
388 }
389
390 public void testAnonymousClassWithTwoParametersConstructor() {
391 abstract class Base {
392 @SuppressWarnings("unused")
393 Base(String s, int i) {}
394 }
395 Class<?> anonymous = new Base("test", 0) {}.getClass();
396 Constructor<?> constructor = anonymous.getDeclaredConstructors() [0];
397 assertEquals(2, Invokable.from(constructor).getParameters().size());
398 }
399
400 public void testLocalClassDefaultConstructor() {
401 final int i = 1;
402 final String s = "hello world";
403 class LocalWithDefaultConstructor implements Runnable {
404 @Override public void run() {
405 System.out.println(s + i);
406 }
407 }
408 Constructor<?> constructor = LocalWithDefaultConstructor.class.getDeclaredConstructors() [0];
409 assertEquals(0, Invokable.from(constructor).getParameters().size());
410 }
411
412 public void testStaticAnonymousClassDefaultConstructor() throws Exception {
413 doTestStaticAnonymousClassDefaultConstructor();
414 }
415
416 private static void doTestStaticAnonymousClassDefaultConstructor() {
417 final int i = 1;
418 final String s = "hello world";
419 Class<?> anonymous = new Runnable() {
420 @Override public void run() {
421 System.out.println(s + i);
422 }
423 }.getClass();
424 Constructor<?> constructor = anonymous.getDeclaredConstructors() [0];
425 assertEquals(0, Invokable.from(constructor).getParameters().size());
426 }
427
428 public void testAnonymousClassInConstructor() {
429 new AnonymousClassInConstructor();
430 }
431
432 private static class AnonymousClassInConstructor {
433 AnonymousClassInConstructor() {
434 final int i = 1;
435 final String s = "hello world";
436 Class<?> anonymous = new Runnable() {
437 @Override public void run() {
438 System.out.println(s + i);
439 }
440 }.getClass();
441 Constructor<?> constructor = anonymous.getDeclaredConstructors() [0];
442 assertEquals(0, Invokable.from(constructor).getParameters().size());
443 }
444 }
445
446 public void testLocalClassInInstanceInitializer() {
447 new LocalClassInInstanceInitializer();
448 }
449
450 private static class LocalClassInInstanceInitializer {
451 {
452 class Local {}
453 Constructor<?> constructor = Local.class.getDeclaredConstructors() [0];
454 assertEquals(0, Invokable.from(constructor).getParameters().size());
455 }
456 }
457
458 public void testLocalClassInStaticInitializer() {
459 new LocalClassInStaticInitializer();
460 }
461
462 private static class LocalClassInStaticInitializer {
463 static {
464 class Local {}
465 Constructor<?> constructor = Local.class.getDeclaredConstructors() [0];
466 assertEquals(0, Invokable.from(constructor).getParameters().size());
467 }
468 }
469
470 public void testLocalClassWithSeeminglyHiddenThisInStaticInitializer_BUG() {
471 new LocalClassWithSeeminglyHiddenThisInStaticInitializer();
472 }
473
474
475
476
477
478 private static class LocalClassWithSeeminglyHiddenThisInStaticInitializer {
479 static {
480 class Local {
481 @SuppressWarnings("unused")
482 Local(LocalClassWithSeeminglyHiddenThisInStaticInitializer outer) {}
483 }
484 Constructor<?> constructor = Local.class.getDeclaredConstructors() [0];
485 int miscalculated = 0;
486 assertEquals(miscalculated, Invokable.from(constructor).getParameters().size());
487 }
488 }
489
490 public void testLocalClassWithOneParameterConstructor() throws Exception {
491 final int i = 1;
492 final String s = "hello world";
493 class LocalWithOneParameterConstructor {
494 @SuppressWarnings("unused")
495 public LocalWithOneParameterConstructor(String x) {
496 System.out.println(s + i);
497 }
498 }
499 Constructor<?> constructor =
500 LocalWithOneParameterConstructor.class.getDeclaredConstructors()[0];
501 Invokable<?, ?> invokable = Invokable.from(constructor);
502 assertEquals(1, invokable.getParameters().size());
503 assertEquals(TypeToken.of(String.class), invokable.getParameters().get(0).getType());
504 }
505
506 public void testLocalClassWithAnnotatedConstructorParameter() throws Exception {
507 class LocalWithAnnotatedConstructorParameter {
508 @SuppressWarnings("unused")
509 LocalWithAnnotatedConstructorParameter(@Nullable String s) {}
510 }
511 Constructor<?> constructor =
512 LocalWithAnnotatedConstructorParameter.class.getDeclaredConstructors() [0];
513 Invokable<?, ?> invokable = Invokable.from(constructor);
514 assertEquals(1, invokable.getParameters().size());
515 assertEquals(TypeToken.of(String.class), invokable.getParameters().get(0).getType());
516 }
517
518 public void testLocalClassWithGenericConstructorParameter() throws Exception {
519 class LocalWithGenericConstructorParameter {
520 @SuppressWarnings("unused")
521 LocalWithGenericConstructorParameter(Iterable<String> it, String s) {}
522 }
523 Constructor<?> constructor =
524 LocalWithGenericConstructorParameter.class.getDeclaredConstructors() [0];
525 Invokable<?, ?> invokable = Invokable.from(constructor);
526 assertEquals(2, invokable.getParameters().size());
527 assertEquals(new TypeToken<Iterable<String>>() {},
528 invokable.getParameters().get(0).getType());
529 assertEquals(TypeToken.of(String.class),
530 invokable.getParameters().get(1).getType());
531 }
532
533 public void testEquals() throws Exception {
534 new EqualsTester()
535 .addEqualityGroup(Prepender.constructor(), Prepender.constructor())
536 .addEqualityGroup(Prepender.constructor(String.class, int.class))
537 .addEqualityGroup(Prepender.method("privateMethod"), Prepender.method("privateMethod"))
538 .addEqualityGroup(Prepender.method("privateFinalMethod"))
539 .testEquals();
540 }
541
542 public void testNulls() {
543 new NullPointerTester().testAllPublicStaticMethods(Invokable.class);
544 new NullPointerTester().testAllPublicInstanceMethods(Prepender.method("staticMethod"));
545 }
546
547 @Retention(RetentionPolicy.RUNTIME)
548 private @interface NotBlank {}
549
550
551 @SuppressWarnings("unused")
552 private static class Prepender {
553
554 private final String prefix;
555 private final int times;
556
557 Prepender(@NotBlank String prefix, int times) throws NullPointerException {
558 this.prefix = prefix;
559 this.times = times;
560 }
561
562 Prepender(String... varargs) {
563 this(null, 0);
564 }
565
566
567 private <A> Prepender() {
568 this(null, 0);
569 }
570
571 static <T> Iterable<String> prepend(@NotBlank String first, Iterable<String> tail) {
572 return Iterables.concat(ImmutableList.of(first), tail);
573 }
574
575 Iterable<String> prepend(Iterable<String> tail)
576 throws IllegalArgumentException, NullPointerException {
577 return Iterables.concat(Collections.nCopies(times, prefix), tail);
578 }
579
580 static Invokable<?, Prepender> constructor(Class<?>... parameterTypes) throws Exception {
581 Constructor<Prepender> constructor = Prepender.class.getDeclaredConstructor(parameterTypes);
582 return Invokable.from(constructor);
583 }
584
585 static Invokable<Prepender, Object> method(String name, Class<?>... parameterTypes) {
586 try {
587 Method method = Prepender.class.getDeclaredMethod(name, parameterTypes);
588 @SuppressWarnings("unchecked")
589 Invokable<Prepender, Object> invokable = (Invokable<Prepender, Object>)
590 Invokable.from(method);
591 return invokable;
592 } catch (NoSuchMethodException e) {
593 throw new IllegalArgumentException(e);
594 }
595 }
596
597 private void privateMethod() {}
598
599 private final void privateFinalMethod() {}
600
601 static void staticMethod() {}
602
603 static final void staticFinalMethod() {}
604
605 private void privateVarArgsMethod(String... varargs) {}
606 }
607
608 private static class SubPrepender extends Prepender {
609 @SuppressWarnings("unused")
610 public SubPrepender() throws NullPointerException {
611 throw new AssertionError();
612 }
613 }
614 }