1 /* 2 * Copyright (C) 2012 The Guava 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 com.google.common.reflect; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import com.google.common.collect.ImmutableList; 22 import com.google.common.collect.Iterables; 23 import com.google.common.testing.EqualsTester; 24 import com.google.common.testing.NullPointerTester; 25 import java.lang.annotation.Retention; 26 import java.lang.annotation.RetentionPolicy; 27 import java.lang.reflect.Constructor; 28 import java.lang.reflect.Method; 29 import java.lang.reflect.ParameterizedType; 30 import java.lang.reflect.TypeVariable; 31 import java.util.Collections; 32 import junit.framework.TestCase; 33 import org.checkerframework.checker.nullness.compatqual.NullableDecl; 34 35 /** 36 * Unit tests for {@link Invokable}. 37 * 38 * @author Ben Yu 39 */ 40 @AndroidIncompatible // lots of failures, possibly some related to bad equals() implementations? 41 public class InvokableTest extends TestCase { 42 testConstructor_returnType()43 public void testConstructor_returnType() throws Exception { 44 assertEquals(Prepender.class, Prepender.constructor().getReturnType().getType()); 45 } 46 47 private static class WithConstructorAndTypeParameter<T> { 48 @SuppressWarnings("unused") // by reflection WithConstructorAndTypeParameter()49 <X> WithConstructorAndTypeParameter() {} 50 } 51 testConstructor_returnType_hasTypeParameter()52 public void testConstructor_returnType_hasTypeParameter() throws Exception { 53 @SuppressWarnings("rawtypes") // Foo.class for Foo<T> is always raw type 54 Class<WithConstructorAndTypeParameter> type = WithConstructorAndTypeParameter.class; 55 @SuppressWarnings("rawtypes") // Foo.class 56 Constructor<WithConstructorAndTypeParameter> constructor = type.getDeclaredConstructor(); 57 Invokable<?, ?> factory = Invokable.from(constructor); 58 assertThat(factory.getTypeParameters()).hasLength(2); 59 assertEquals(type.getTypeParameters()[0], factory.getTypeParameters()[0]); 60 assertEquals(constructor.getTypeParameters()[0], factory.getTypeParameters()[1]); 61 ParameterizedType returnType = (ParameterizedType) factory.getReturnType().getType(); 62 assertEquals(type, returnType.getRawType()); 63 assertEquals( 64 ImmutableList.copyOf(type.getTypeParameters()), 65 ImmutableList.copyOf(returnType.getActualTypeArguments())); 66 } 67 testConstructor_exceptionTypes()68 public void testConstructor_exceptionTypes() throws Exception { 69 assertEquals( 70 ImmutableList.of(TypeToken.of(NullPointerException.class)), 71 Prepender.constructor(String.class, int.class).getExceptionTypes()); 72 } 73 testConstructor_typeParameters()74 public void testConstructor_typeParameters() throws Exception { 75 TypeVariable<?>[] variables = Prepender.constructor().getTypeParameters(); 76 assertThat(variables).hasLength(1); 77 assertEquals("A", variables[0].getName()); 78 } 79 testConstructor_parameters()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 testConstructor_call()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 testConstructor_returning()101 public void testConstructor_returning() throws Exception { 102 Invokable<?, Prepender> delegate = 103 Prepender.constructor(String.class, int.class).returning(Prepender.class); 104 Prepender prepender = delegate.invoke(null, "a", 1); 105 assertEquals("a", prepender.prefix); 106 assertEquals(1, prepender.times); 107 } 108 testConstructor_invalidReturning()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 testStaticMethod_returnType()118 public void testStaticMethod_returnType() throws Exception { 119 Invokable<?, ?> delegate = Prepender.method("prepend", String.class, Iterable.class); 120 assertEquals(new TypeToken<Iterable<String>>() {}, delegate.getReturnType()); 121 } 122 testStaticMethod_exceptionTypes()123 public void testStaticMethod_exceptionTypes() throws Exception { 124 Invokable<?, ?> delegate = Prepender.method("prepend", String.class, Iterable.class); 125 assertEquals(ImmutableList.of(), delegate.getExceptionTypes()); 126 } 127 testStaticMethod_typeParameters()128 public void testStaticMethod_typeParameters() throws Exception { 129 Invokable<?, ?> delegate = Prepender.method("prepend", String.class, Iterable.class); 130 TypeVariable<?>[] variables = delegate.getTypeParameters(); 131 assertThat(variables).hasLength(1); 132 assertEquals("T", variables[0].getName()); 133 } 134 testStaticMethod_parameters()135 public void testStaticMethod_parameters() throws Exception { 136 Invokable<?, ?> delegate = Prepender.method("prepend", String.class, Iterable.class); 137 ImmutableList<Parameter> parameters = delegate.getParameters(); 138 assertEquals(2, parameters.size()); 139 assertEquals(String.class, parameters.get(0).getType().getType()); 140 assertTrue(parameters.get(0).isAnnotationPresent(NotBlank.class)); 141 assertEquals(new TypeToken<Iterable<String>>() {}, parameters.get(1).getType()); 142 assertFalse(parameters.get(1).isAnnotationPresent(NotBlank.class)); 143 new EqualsTester() 144 .addEqualityGroup(parameters.get(0)) 145 .addEqualityGroup(parameters.get(1)) 146 .testEquals(); 147 } 148 testStaticMethod_call()149 public void testStaticMethod_call() throws Exception { 150 Invokable<?, ?> delegate = Prepender.method("prepend", String.class, Iterable.class); 151 @SuppressWarnings("unchecked") // prepend() returns Iterable<String> 152 Iterable<String> result = 153 (Iterable<String>) delegate.invoke(null, "a", ImmutableList.of("b", "c")); 154 assertEquals(ImmutableList.of("a", "b", "c"), ImmutableList.copyOf(result)); 155 } 156 testStaticMethod_returning()157 public void testStaticMethod_returning() throws Exception { 158 Invokable<?, Iterable<String>> delegate = 159 Prepender.method("prepend", String.class, Iterable.class) 160 .returning(new TypeToken<Iterable<String>>() {}); 161 assertEquals(new TypeToken<Iterable<String>>() {}, delegate.getReturnType()); 162 Iterable<String> result = delegate.invoke(null, "a", ImmutableList.of("b", "c")); 163 assertEquals(ImmutableList.of("a", "b", "c"), ImmutableList.copyOf(result)); 164 } 165 testStaticMethod_returningRawType()166 public void testStaticMethod_returningRawType() throws Exception { 167 @SuppressWarnings("rawtypes") // the purpose is to test raw type 168 Invokable<?, Iterable> delegate = 169 Prepender.method("prepend", String.class, Iterable.class).returning(Iterable.class); 170 assertEquals(new TypeToken<Iterable<String>>() {}, delegate.getReturnType()); 171 @SuppressWarnings("unchecked") // prepend() returns Iterable<String> 172 Iterable<String> result = delegate.invoke(null, "a", ImmutableList.of("b", "c")); 173 assertEquals(ImmutableList.of("a", "b", "c"), ImmutableList.copyOf(result)); 174 } 175 testStaticMethod_invalidReturning()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 testInstanceMethod_returnType()185 public void testInstanceMethod_returnType() throws Exception { 186 Invokable<?, ?> delegate = Prepender.method("prepend", Iterable.class); 187 assertEquals(new TypeToken<Iterable<String>>() {}, delegate.getReturnType()); 188 } 189 testInstanceMethod_exceptionTypes()190 public void testInstanceMethod_exceptionTypes() throws Exception { 191 Invokable<?, ?> delegate = Prepender.method("prepend", Iterable.class); 192 assertEquals( 193 ImmutableList.of( 194 TypeToken.of(IllegalArgumentException.class), TypeToken.of(NullPointerException.class)), 195 delegate.getExceptionTypes()); 196 } 197 testInstanceMethod_typeParameters()198 public void testInstanceMethod_typeParameters() throws Exception { 199 Invokable<?, ?> delegate = Prepender.method("prepend", Iterable.class); 200 assertThat(delegate.getTypeParameters()).isEmpty(); 201 } 202 testInstanceMethod_parameters()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 assertThat(parameters.get(0).getAnnotations()).isEmpty(); 209 new EqualsTester().addEqualityGroup(parameters.get(0)).testEquals(); 210 } 211 testInstanceMethod_call()212 public void testInstanceMethod_call() throws Exception { 213 Invokable<Prepender, ?> delegate = Prepender.method("prepend", Iterable.class); 214 @SuppressWarnings("unchecked") // prepend() returns Iterable<String> 215 Iterable<String> result = 216 (Iterable<String>) delegate.invoke(new Prepender("a", 2), ImmutableList.of("b", "c")); 217 assertEquals(ImmutableList.of("a", "a", "b", "c"), ImmutableList.copyOf(result)); 218 } 219 testInstanceMethod_returning()220 public void testInstanceMethod_returning() throws Exception { 221 Invokable<Prepender, Iterable<String>> delegate = 222 Prepender.method("prepend", Iterable.class).returning(new TypeToken<Iterable<String>>() {}); 223 assertEquals(new TypeToken<Iterable<String>>() {}, delegate.getReturnType()); 224 Iterable<String> result = delegate.invoke(new Prepender("a", 2), ImmutableList.of("b", "c")); 225 assertEquals(ImmutableList.of("a", "a", "b", "c"), ImmutableList.copyOf(result)); 226 } 227 testInstanceMethod_returningRawType()228 public void testInstanceMethod_returningRawType() throws Exception { 229 @SuppressWarnings("rawtypes") // the purpose is to test raw type 230 Invokable<Prepender, Iterable> delegate = 231 Prepender.method("prepend", Iterable.class).returning(Iterable.class); 232 assertEquals(new TypeToken<Iterable<String>>() {}, delegate.getReturnType()); 233 @SuppressWarnings("unchecked") // prepend() returns Iterable<String> 234 Iterable<String> result = delegate.invoke(new Prepender("a", 2), ImmutableList.of("b", "c")); 235 assertEquals(ImmutableList.of("a", "a", "b", "c"), ImmutableList.copyOf(result)); 236 } 237 testInstanceMethod_invalidReturning()238 public void testInstanceMethod_invalidReturning() throws Exception { 239 Invokable<?, Object> delegate = Prepender.method("prepend", Iterable.class); 240 try { 241 delegate.returning(new TypeToken<Iterable<Integer>>() {}); 242 fail(); 243 } catch (IllegalArgumentException expected) { 244 } 245 } 246 testPrivateInstanceMethod_isOverridable()247 public void testPrivateInstanceMethod_isOverridable() throws Exception { 248 Invokable<?, ?> delegate = Prepender.method("privateMethod"); 249 assertTrue(delegate.isPrivate()); 250 assertFalse(delegate.isOverridable()); 251 assertFalse(delegate.isVarArgs()); 252 } 253 testPrivateFinalInstanceMethod_isOverridable()254 public void testPrivateFinalInstanceMethod_isOverridable() throws Exception { 255 Invokable<?, ?> delegate = Prepender.method("privateFinalMethod"); 256 assertTrue(delegate.isPrivate()); 257 assertTrue(delegate.isFinal()); 258 assertFalse(delegate.isOverridable()); 259 assertFalse(delegate.isVarArgs()); 260 } 261 testStaticMethod_isOverridable()262 public void testStaticMethod_isOverridable() throws Exception { 263 Invokable<?, ?> delegate = Prepender.method("staticMethod"); 264 assertTrue(delegate.isStatic()); 265 assertFalse(delegate.isOverridable()); 266 assertFalse(delegate.isVarArgs()); 267 } 268 testStaticFinalMethod_isFinal()269 public void testStaticFinalMethod_isFinal() throws Exception { 270 Invokable<?, ?> delegate = Prepender.method("staticFinalMethod"); 271 assertTrue(delegate.isStatic()); 272 assertTrue(delegate.isFinal()); 273 assertFalse(delegate.isOverridable()); 274 assertFalse(delegate.isVarArgs()); 275 } 276 277 static class Foo {} 278 testConstructor_isOverridablel()279 public void testConstructor_isOverridablel() throws Exception { 280 Invokable<?, ?> delegate = Invokable.from(Foo.class.getDeclaredConstructor()); 281 assertFalse(delegate.isOverridable()); 282 assertFalse(delegate.isVarArgs()); 283 } 284 testMethod_isVarArgs()285 public void testMethod_isVarArgs() throws Exception { 286 Invokable<?, ?> delegate = Prepender.method("privateVarArgsMethod", String[].class); 287 assertTrue(delegate.isVarArgs()); 288 } 289 testConstructor_isVarArgs()290 public void testConstructor_isVarArgs() throws Exception { 291 Invokable<?, ?> delegate = Prepender.constructor(String[].class); 292 assertTrue(delegate.isVarArgs()); 293 } 294 testGetOwnerType_constructor()295 public void testGetOwnerType_constructor() throws Exception { 296 Invokable<String, String> invokable = Invokable.from(String.class.getConstructor()); 297 assertEquals(TypeToken.of(String.class), invokable.getOwnerType()); 298 } 299 testGetOwnerType_method()300 public void testGetOwnerType_method() throws Exception { 301 Invokable<?, ?> invokable = Invokable.from(String.class.getMethod("length")); 302 assertEquals(TypeToken.of(String.class), invokable.getOwnerType()); 303 } 304 305 private static final class FinalClass { 306 @SuppressWarnings("unused") // used by reflection notFinalMethod()307 void notFinalMethod() {} 308 } 309 testNonFinalMethodInFinalClass_isOverridable()310 public void testNonFinalMethodInFinalClass_isOverridable() throws Exception { 311 Invokable<?, ?> delegate = Invokable.from(FinalClass.class.getDeclaredMethod("notFinalMethod")); 312 assertFalse(delegate.isOverridable()); 313 assertFalse(delegate.isVarArgs()); 314 } 315 316 private class InnerWithDefaultConstructor { 317 class NestedInner {} 318 } 319 testInnerClassDefaultConstructor()320 public void testInnerClassDefaultConstructor() { 321 Constructor<?> constructor = InnerWithDefaultConstructor.class.getDeclaredConstructors()[0]; 322 assertEquals(0, Invokable.from(constructor).getParameters().size()); 323 } 324 testNestedInnerClassDefaultConstructor()325 public void testNestedInnerClassDefaultConstructor() { 326 Constructor<?> constructor = 327 InnerWithDefaultConstructor.NestedInner.class.getDeclaredConstructors()[0]; 328 assertEquals(0, Invokable.from(constructor).getParameters().size()); 329 } 330 331 private class InnerWithOneParameterConstructor { 332 @SuppressWarnings("unused") // called by reflection InnerWithOneParameterConstructor(String s)333 public InnerWithOneParameterConstructor(String s) {} 334 } 335 testInnerClassWithOneParameterConstructor()336 public void testInnerClassWithOneParameterConstructor() { 337 Constructor<?> constructor = 338 InnerWithOneParameterConstructor.class.getDeclaredConstructors()[0]; 339 Invokable<?, ?> invokable = Invokable.from(constructor); 340 assertEquals(1, invokable.getParameters().size()); 341 assertEquals(TypeToken.of(String.class), invokable.getParameters().get(0).getType()); 342 } 343 344 private class InnerWithAnnotatedConstructorParameter { 345 @SuppressWarnings("unused") // called by reflection InnerWithAnnotatedConstructorParameter(@ullableDecl String s)346 InnerWithAnnotatedConstructorParameter(@NullableDecl String s) {} 347 } 348 testInnerClassWithAnnotatedConstructorParameter()349 public void testInnerClassWithAnnotatedConstructorParameter() { 350 Constructor<?> constructor = 351 InnerWithAnnotatedConstructorParameter.class.getDeclaredConstructors()[0]; 352 Invokable<?, ?> invokable = Invokable.from(constructor); 353 assertEquals(1, invokable.getParameters().size()); 354 assertEquals(TypeToken.of(String.class), invokable.getParameters().get(0).getType()); 355 } 356 357 private class InnerWithGenericConstructorParameter { 358 @SuppressWarnings("unused") // called by reflection InnerWithGenericConstructorParameter(Iterable<String> it, String s)359 InnerWithGenericConstructorParameter(Iterable<String> it, String s) {} 360 } 361 testInnerClassWithGenericConstructorParameter()362 public void testInnerClassWithGenericConstructorParameter() { 363 Constructor<?> constructor = 364 InnerWithGenericConstructorParameter.class.getDeclaredConstructors()[0]; 365 Invokable<?, ?> invokable = Invokable.from(constructor); 366 assertEquals(2, invokable.getParameters().size()); 367 assertEquals(new TypeToken<Iterable<String>>() {}, invokable.getParameters().get(0).getType()); 368 assertEquals(TypeToken.of(String.class), invokable.getParameters().get(1).getType()); 369 } 370 testAnonymousClassDefaultConstructor()371 public void testAnonymousClassDefaultConstructor() { 372 final int i = 1; 373 final String s = "hello world"; 374 Class<?> anonymous = 375 new Runnable() { 376 @Override 377 public void run() { 378 System.out.println(s + i); 379 } 380 }.getClass(); 381 Constructor<?> constructor = anonymous.getDeclaredConstructors()[0]; 382 assertEquals(0, Invokable.from(constructor).getParameters().size()); 383 } 384 testAnonymousClassWithTwoParametersConstructor()385 public void testAnonymousClassWithTwoParametersConstructor() { 386 abstract class Base { 387 @SuppressWarnings("unused") // called by reflection 388 Base(String s, int i) {} 389 } 390 Class<?> anonymous = new Base("test", 0) {}.getClass(); 391 Constructor<?> constructor = anonymous.getDeclaredConstructors()[0]; 392 assertEquals(2, Invokable.from(constructor).getParameters().size()); 393 } 394 testLocalClassDefaultConstructor()395 public void testLocalClassDefaultConstructor() { 396 final int i = 1; 397 final String s = "hello world"; 398 class LocalWithDefaultConstructor implements Runnable { 399 @Override 400 public void run() { 401 System.out.println(s + i); 402 } 403 } 404 Constructor<?> constructor = LocalWithDefaultConstructor.class.getDeclaredConstructors()[0]; 405 assertEquals(0, Invokable.from(constructor).getParameters().size()); 406 } 407 testStaticAnonymousClassDefaultConstructor()408 public void testStaticAnonymousClassDefaultConstructor() throws Exception { 409 doTestStaticAnonymousClassDefaultConstructor(); 410 } 411 doTestStaticAnonymousClassDefaultConstructor()412 private static void doTestStaticAnonymousClassDefaultConstructor() { 413 final int i = 1; 414 final String s = "hello world"; 415 Class<?> anonymous = 416 new Runnable() { 417 @Override 418 public void run() { 419 System.out.println(s + i); 420 } 421 }.getClass(); 422 Constructor<?> constructor = anonymous.getDeclaredConstructors()[0]; 423 assertEquals(0, Invokable.from(constructor).getParameters().size()); 424 } 425 testAnonymousClassInConstructor()426 public void testAnonymousClassInConstructor() { 427 new AnonymousClassInConstructor(); 428 } 429 430 private static class AnonymousClassInConstructor { AnonymousClassInConstructor()431 AnonymousClassInConstructor() { 432 final int i = 1; 433 final String s = "hello world"; 434 Class<?> anonymous = 435 new Runnable() { 436 @Override 437 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 testLocalClassInInstanceInitializer()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 testLocalClassInStaticInitializer()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 testLocalClassWithSeeminglyHiddenThisInStaticInitializer_BUG()470 public void testLocalClassWithSeeminglyHiddenThisInStaticInitializer_BUG() { 471 new LocalClassWithSeeminglyHiddenThisInStaticInitializer(); 472 } 473 474 /** 475 * This class demonstrates a bug in getParameters() when the local class is inside static 476 * initializer. 477 */ 478 private static class LocalClassWithSeeminglyHiddenThisInStaticInitializer { 479 static { 480 class Local { 481 @SuppressWarnings("unused") // through reflection Local(LocalClassWithSeeminglyHiddenThisInStaticInitializer outer)482 Local(LocalClassWithSeeminglyHiddenThisInStaticInitializer outer) {} 483 } 484 Constructor<?> constructor = Local.class.getDeclaredConstructors()[0]; 485 int miscalculated = 0; assertEquals(miscalculated, Invokable.from(constructor).getParameters().size())486 assertEquals(miscalculated, Invokable.from(constructor).getParameters().size()); 487 } 488 } 489 testLocalClassWithOneParameterConstructor()490 public void testLocalClassWithOneParameterConstructor() throws Exception { 491 final int i = 1; 492 final String s = "hello world"; 493 class LocalWithOneParameterConstructor { 494 @SuppressWarnings("unused") // called by reflection 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 testLocalClassWithAnnotatedConstructorParameter()506 public void testLocalClassWithAnnotatedConstructorParameter() throws Exception { 507 class LocalWithAnnotatedConstructorParameter { 508 @SuppressWarnings("unused") // called by reflection 509 LocalWithAnnotatedConstructorParameter(@NullableDecl 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 testLocalClassWithGenericConstructorParameter()518 public void testLocalClassWithGenericConstructorParameter() throws Exception { 519 class LocalWithGenericConstructorParameter { 520 @SuppressWarnings("unused") // called by reflection 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>>() {}, invokable.getParameters().get(0).getType()); 528 assertEquals(TypeToken.of(String.class), invokable.getParameters().get(1).getType()); 529 } 530 testEquals()531 public void testEquals() throws Exception { 532 new EqualsTester() 533 .addEqualityGroup(Prepender.constructor(), Prepender.constructor()) 534 .addEqualityGroup(Prepender.constructor(String.class, int.class)) 535 .addEqualityGroup(Prepender.method("privateMethod"), Prepender.method("privateMethod")) 536 .addEqualityGroup(Prepender.method("privateFinalMethod")) 537 .testEquals(); 538 } 539 testNulls()540 public void testNulls() { 541 new NullPointerTester().testAllPublicStaticMethods(Invokable.class); 542 new NullPointerTester().testAllPublicInstanceMethods(Prepender.method("staticMethod")); 543 } 544 545 @Retention(RetentionPolicy.RUNTIME) 546 private @interface NotBlank {} 547 548 /** Class for testing constructor, static method and instance method. */ 549 @SuppressWarnings("unused") // most are called by reflection 550 private static class Prepender { 551 552 private final String prefix; 553 private final int times; 554 Prepender(@otBlank String prefix, int times)555 Prepender(@NotBlank String prefix, int times) throws NullPointerException { 556 this.prefix = prefix; 557 this.times = times; 558 } 559 Prepender(String... varargs)560 Prepender(String... varargs) { 561 this(null, 0); 562 } 563 564 // just for testing Prepender()565 private <A> Prepender() { 566 this(null, 0); 567 } 568 prepend(@otBlank String first, Iterable<String> tail)569 static <T> Iterable<String> prepend(@NotBlank String first, Iterable<String> tail) { 570 return Iterables.concat(ImmutableList.of(first), tail); 571 } 572 prepend(Iterable<String> tail)573 Iterable<String> prepend(Iterable<String> tail) 574 throws IllegalArgumentException, NullPointerException { 575 return Iterables.concat(Collections.nCopies(times, prefix), tail); 576 } 577 constructor(Class<?>.... parameterTypes)578 static Invokable<?, Prepender> constructor(Class<?>... parameterTypes) throws Exception { 579 Constructor<Prepender> constructor = Prepender.class.getDeclaredConstructor(parameterTypes); 580 return Invokable.from(constructor); 581 } 582 method(String name, Class<?>... parameterTypes)583 static Invokable<Prepender, Object> method(String name, Class<?>... parameterTypes) { 584 try { 585 Method method = Prepender.class.getDeclaredMethod(name, parameterTypes); 586 @SuppressWarnings("unchecked") // The method is from Prepender. 587 Invokable<Prepender, Object> invokable = 588 (Invokable<Prepender, Object>) Invokable.from(method); 589 return invokable; 590 } catch (NoSuchMethodException e) { 591 throw new IllegalArgumentException(e); 592 } 593 } 594 privateMethod()595 private void privateMethod() {} 596 privateFinalMethod()597 private final void privateFinalMethod() {} 598 staticMethod()599 static void staticMethod() {} 600 staticFinalMethod()601 static final void staticFinalMethod() {} 602 privateVarArgsMethod(String... varargs)603 private void privateVarArgsMethod(String... varargs) {} 604 } 605 606 private static class SubPrepender extends Prepender { 607 @SuppressWarnings("unused") // needed to satisfy compiler, never called SubPrepender()608 public SubPrepender() throws NullPointerException { 609 throw new AssertionError(); 610 } 611 } 612 } 613