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 import static org.junit.Assert.assertThrows; 21 22 import com.google.common.collect.ImmutableList; 23 import com.google.common.collect.ImmutableSet; 24 import com.google.common.collect.Iterables; 25 import com.google.common.testing.EqualsTester; 26 import com.google.common.testing.NullPointerTester; 27 import java.lang.annotation.Retention; 28 import java.lang.annotation.RetentionPolicy; 29 import java.lang.reflect.AccessibleObject; 30 import java.lang.reflect.Constructor; 31 import java.lang.reflect.Method; 32 import java.lang.reflect.Modifier; 33 import java.lang.reflect.ParameterizedType; 34 import java.lang.reflect.TypeVariable; 35 import java.util.Collections; 36 import junit.framework.TestCase; 37 import org.checkerframework.checker.nullness.qual.Nullable; 38 39 /** 40 * Unit tests for {@link Invokable}. 41 * 42 * @author Ben Yu 43 */ 44 @AndroidIncompatible // lots of failures, possibly some related to bad equals() implementations? 45 public class InvokableTest extends TestCase { 46 // Historically Invokable inherited from java.lang.reflect.AccessibleObject. That's no longer the 47 // case, but we do check that its API still has the same public methods. We exclude some methods 48 // that were added in Java 9 and that people probably weren't calling via Invokable, namely 49 // `boolean canAccess(Object)`. testApiCompatibleWithAccessibleObject()50 public void testApiCompatibleWithAccessibleObject() { 51 ImmutableSet<String> invokableMethods = 52 publicMethodSignatures(Invokable.class, ImmutableSet.<String>of()); 53 ImmutableSet<String> accessibleObjectMethods = 54 publicMethodSignatures(AccessibleObject.class, ImmutableSet.of("canAccess")); 55 assertThat(invokableMethods).containsAtLeastElementsIn(accessibleObjectMethods); 56 Class<?> genericDeclaration; 57 try { 58 genericDeclaration = Class.forName("java.lang.reflect.GenericDeclaration"); 59 ImmutableSet<String> genericDeclarationMethods = 60 publicMethodSignatures(genericDeclaration, ImmutableSet.<String>of()); 61 assertThat(invokableMethods).containsAtLeastElementsIn(genericDeclarationMethods); 62 } catch (ClassNotFoundException e) { 63 // OK: we're on Java 7, which doesn't have this class 64 } 65 } 66 publicMethodSignatures( Class<?> c, ImmutableSet<String> ignore)67 private static ImmutableSet<String> publicMethodSignatures( 68 Class<?> c, ImmutableSet<String> ignore) { 69 ImmutableSet.Builder<String> methods = ImmutableSet.builder(); 70 for (Method method : c.getMethods()) { 71 if (Modifier.isStatic(method.getModifiers()) || ignore.contains(method.getName())) { 72 continue; 73 } 74 StringBuilder signature = 75 new StringBuilder() 76 .append(typeName(method.getReturnType())) 77 .append(" ") 78 .append(method.getName()) 79 .append("("); 80 String sep = ""; 81 for (Class<?> param : method.getParameterTypes()) { 82 signature.append(sep).append(typeName(param)); 83 sep = ", "; 84 } 85 methods.add(signature.append(")").toString()); 86 } 87 return methods.build(); 88 } 89 typeName(Class<?> type)90 private static String typeName(Class<?> type) { 91 return type.isArray() ? typeName(type.getComponentType()) + "[]" : type.getName(); 92 } 93 testConstructor()94 public void testConstructor() throws Exception { 95 Invokable<A, A> invokable = A.constructor(); 96 assertTrue(invokable.isPublic()); 97 assertFalse(invokable.isPackagePrivate()); 98 assertFalse(invokable.isAbstract()); 99 assertFalse(invokable.isStatic()); 100 assertTrue(invokable.isAnnotationPresent(Tested.class)); 101 } 102 testAbstractMethod()103 public void testAbstractMethod() throws Exception { 104 Invokable<?, Object> invokable = A.method("abstractMethod"); 105 assertTrue(invokable.isPackagePrivate()); 106 assertTrue(invokable.isAbstract()); 107 assertFalse(invokable.isFinal()); 108 assertTrue(invokable.isAnnotationPresent(Tested.class)); 109 } 110 testOverridableMethod()111 public void testOverridableMethod() throws Exception { 112 Invokable<?, Object> invokable = A.method("overridableMethod"); 113 assertTrue(invokable.isPackagePrivate()); 114 assertFalse(invokable.isAbstract()); 115 assertFalse(invokable.isFinal()); 116 assertTrue(invokable.isAnnotationPresent(Tested.class)); 117 } 118 testPrivateMethod()119 public void testPrivateMethod() throws Exception { 120 Invokable<?, Object> invokable = A.method("privateMethod"); 121 assertFalse(invokable.isAbstract()); 122 assertTrue(invokable.isPrivate()); 123 assertFalse(invokable.isPackagePrivate()); 124 assertFalse(invokable.isPublic()); 125 assertFalse(invokable.isProtected()); 126 assertTrue(invokable.isAnnotationPresent(Tested.class)); 127 } 128 testProtectedMethod()129 public void testProtectedMethod() throws Exception { 130 Invokable<?, Object> invokable = A.method("protectedMethod"); 131 assertFalse(invokable.isAbstract()); 132 assertFalse(invokable.isPrivate()); 133 assertFalse(invokable.isPackagePrivate()); 134 assertFalse(invokable.isFinal()); 135 assertFalse(invokable.isPublic()); 136 assertTrue(invokable.isProtected()); 137 assertTrue(invokable.isAnnotationPresent(Tested.class)); 138 } 139 testFinalMethod()140 public void testFinalMethod() throws Exception { 141 Invokable<?, Object> invokable = A.method("publicFinalMethod"); 142 assertFalse(invokable.isAbstract()); 143 assertFalse(invokable.isPrivate()); 144 assertTrue(invokable.isFinal()); 145 assertTrue(invokable.isPublic()); 146 assertTrue(invokable.isAnnotationPresent(Tested.class)); 147 } 148 testNativeMethod()149 public void testNativeMethod() throws Exception { 150 Invokable<?, Object> invokable = A.method("nativeMethod"); 151 assertTrue(invokable.isNative()); 152 assertTrue(invokable.isPackagePrivate()); 153 } 154 testSynchronizedMethod()155 public void testSynchronizedMethod() throws Exception { 156 Invokable<?, Object> invokable = A.method("synchronizedMethod"); 157 assertTrue(invokable.isSynchronized()); 158 } 159 testUnannotatedMethod()160 public void testUnannotatedMethod() throws Exception { 161 Invokable<?, Object> invokable = A.method("notAnnotatedMethod"); 162 assertFalse(invokable.isAnnotationPresent(Tested.class)); 163 } 164 165 @Retention(RetentionPolicy.RUNTIME) 166 private @interface Tested {} 167 168 private abstract static class A { 169 @Tested private boolean privateField; 170 @Tested int packagePrivateField; 171 @Tested protected int protectedField; 172 @Tested public String publicField; 173 @Tested private static Iterable<String> staticField; 174 @Tested private final Object finalField; 175 private volatile char volatileField; 176 private transient long transientField; 177 178 @Tested A(Object finalField)179 public A(Object finalField) { 180 this.finalField = finalField; 181 } 182 183 @Tested abstractMethod()184 abstract void abstractMethod(); 185 186 @Tested overridableMethod()187 void overridableMethod() {} 188 189 @Tested protectedMethod()190 protected void protectedMethod() {} 191 192 @Tested privateMethod()193 private void privateMethod() {} 194 195 @Tested publicFinalMethod()196 public final void publicFinalMethod() {} 197 notAnnotatedMethod()198 void notAnnotatedMethod() {} 199 constructor()200 static Invokable<A, A> constructor() throws Exception { 201 Constructor<A> constructor = A.class.getDeclaredConstructor(Object.class); 202 Invokable<A, A> invokable = Invokable.from(constructor); 203 assertEquals(constructor.getName(), invokable.getName()); 204 assertEquals(A.class, invokable.getDeclaringClass()); 205 return invokable; 206 } 207 method(String name, Class<?>... parameterTypes)208 static Invokable<?, Object> method(String name, Class<?>... parameterTypes) throws Exception { 209 Invokable<?, Object> invokable = 210 Invokable.from(A.class.getDeclaredMethod(name, parameterTypes)); 211 assertEquals(name, invokable.getName()); 212 assertEquals(A.class, invokable.getDeclaringClass()); 213 return invokable; 214 } 215 nativeMethod()216 native void nativeMethod(); 217 synchronizedMethod()218 synchronized void synchronizedMethod() {} 219 } 220 testConstructor_returnType()221 public void testConstructor_returnType() throws Exception { 222 assertEquals(Prepender.class, Prepender.constructor().getReturnType().getType()); 223 } 224 225 private static class WithConstructorAndTypeParameter<T> { 226 @SuppressWarnings("unused") // by reflection WithConstructorAndTypeParameter()227 <X> WithConstructorAndTypeParameter() {} 228 } 229 testConstructor_returnType_hasTypeParameter()230 public void testConstructor_returnType_hasTypeParameter() throws Exception { 231 @SuppressWarnings("rawtypes") // Foo.class for Foo<T> is always raw type 232 Class<WithConstructorAndTypeParameter> type = WithConstructorAndTypeParameter.class; 233 @SuppressWarnings("rawtypes") // Foo.class 234 Constructor<WithConstructorAndTypeParameter> constructor = type.getDeclaredConstructor(); 235 Invokable<?, ?> factory = Invokable.from(constructor); 236 assertThat(factory.getTypeParameters()).hasLength(2); 237 assertEquals(type.getTypeParameters()[0], factory.getTypeParameters()[0]); 238 assertEquals(constructor.getTypeParameters()[0], factory.getTypeParameters()[1]); 239 ParameterizedType returnType = (ParameterizedType) factory.getReturnType().getType(); 240 assertEquals(type, returnType.getRawType()); 241 assertEquals( 242 ImmutableList.copyOf(type.getTypeParameters()), 243 ImmutableList.copyOf(returnType.getActualTypeArguments())); 244 } 245 testConstructor_exceptionTypes()246 public void testConstructor_exceptionTypes() throws Exception { 247 assertEquals( 248 ImmutableList.of(TypeToken.of(NullPointerException.class)), 249 Prepender.constructor(String.class, int.class).getExceptionTypes()); 250 } 251 testConstructor_typeParameters()252 public void testConstructor_typeParameters() throws Exception { 253 TypeVariable<?>[] variables = Prepender.constructor().getTypeParameters(); 254 assertThat(variables).hasLength(1); 255 assertEquals("T", variables[0].getName()); 256 } 257 testConstructor_parameters()258 public void testConstructor_parameters() throws Exception { 259 Invokable<?, Prepender> delegate = Prepender.constructor(String.class, int.class); 260 ImmutableList<Parameter> parameters = delegate.getParameters(); 261 assertEquals(2, parameters.size()); 262 assertEquals(String.class, parameters.get(0).getType().getType()); 263 assertTrue(parameters.get(0).isAnnotationPresent(NotBlank.class)); 264 assertEquals(int.class, parameters.get(1).getType().getType()); 265 assertFalse(parameters.get(1).isAnnotationPresent(NotBlank.class)); 266 new EqualsTester() 267 .addEqualityGroup(parameters.get(0)) 268 .addEqualityGroup(parameters.get(1)) 269 .testEquals(); 270 } 271 testConstructor_call()272 public void testConstructor_call() throws Exception { 273 Invokable<?, Prepender> delegate = Prepender.constructor(String.class, int.class); 274 Prepender prepender = delegate.invoke(null, "a", 1); 275 assertEquals("a", prepender.prefix); 276 assertEquals(1, prepender.times); 277 } 278 testConstructor_returning()279 public void testConstructor_returning() throws Exception { 280 Invokable<?, Prepender> delegate = 281 Prepender.constructor(String.class, int.class).returning(Prepender.class); 282 Prepender prepender = delegate.invoke(null, "a", 1); 283 assertEquals("a", prepender.prefix); 284 assertEquals(1, prepender.times); 285 } 286 testConstructor_invalidReturning()287 public void testConstructor_invalidReturning() throws Exception { 288 Invokable<?, Prepender> delegate = Prepender.constructor(String.class, int.class); 289 assertThrows(IllegalArgumentException.class, () -> delegate.returning(SubPrepender.class)); 290 } 291 testStaticMethod_returnType()292 public void testStaticMethod_returnType() throws Exception { 293 Invokable<?, ?> delegate = Prepender.method("prepend", String.class, Iterable.class); 294 assertEquals(new TypeToken<Iterable<String>>() {}, delegate.getReturnType()); 295 } 296 testStaticMethod_exceptionTypes()297 public void testStaticMethod_exceptionTypes() throws Exception { 298 Invokable<?, ?> delegate = Prepender.method("prepend", String.class, Iterable.class); 299 assertEquals(ImmutableList.of(), delegate.getExceptionTypes()); 300 } 301 testStaticMethod_typeParameters()302 public void testStaticMethod_typeParameters() throws Exception { 303 Invokable<?, ?> delegate = Prepender.method("prepend", String.class, Iterable.class); 304 TypeVariable<?>[] variables = delegate.getTypeParameters(); 305 assertThat(variables).hasLength(1); 306 assertEquals("T", variables[0].getName()); 307 } 308 testStaticMethod_parameters()309 public void testStaticMethod_parameters() throws Exception { 310 Invokable<?, ?> delegate = Prepender.method("prepend", String.class, Iterable.class); 311 ImmutableList<Parameter> parameters = delegate.getParameters(); 312 assertEquals(2, parameters.size()); 313 assertEquals(String.class, parameters.get(0).getType().getType()); 314 assertTrue(parameters.get(0).isAnnotationPresent(NotBlank.class)); 315 assertEquals(new TypeToken<Iterable<String>>() {}, parameters.get(1).getType()); 316 assertFalse(parameters.get(1).isAnnotationPresent(NotBlank.class)); 317 new EqualsTester() 318 .addEqualityGroup(parameters.get(0)) 319 .addEqualityGroup(parameters.get(1)) 320 .testEquals(); 321 } 322 testStaticMethod_call()323 public void testStaticMethod_call() throws Exception { 324 Invokable<?, ?> delegate = Prepender.method("prepend", String.class, Iterable.class); 325 @SuppressWarnings("unchecked") // prepend() returns Iterable<String> 326 Iterable<String> result = 327 (Iterable<String>) delegate.invoke(null, "a", ImmutableList.of("b", "c")); 328 assertEquals(ImmutableList.of("a", "b", "c"), ImmutableList.copyOf(result)); 329 } 330 testStaticMethod_returning()331 public void testStaticMethod_returning() throws Exception { 332 Invokable<?, Iterable<String>> delegate = 333 Prepender.method("prepend", String.class, Iterable.class) 334 .returning(new TypeToken<Iterable<String>>() {}); 335 assertEquals(new TypeToken<Iterable<String>>() {}, delegate.getReturnType()); 336 Iterable<String> result = delegate.invoke(null, "a", ImmutableList.of("b", "c")); 337 assertEquals(ImmutableList.of("a", "b", "c"), ImmutableList.copyOf(result)); 338 } 339 testStaticMethod_returningRawType()340 public void testStaticMethod_returningRawType() throws Exception { 341 @SuppressWarnings("rawtypes") // the purpose is to test raw type 342 Invokable<?, Iterable> delegate = 343 Prepender.method("prepend", String.class, Iterable.class).returning(Iterable.class); 344 assertEquals(new TypeToken<Iterable<String>>() {}, delegate.getReturnType()); 345 @SuppressWarnings("unchecked") // prepend() returns Iterable<String> 346 Iterable<String> result = delegate.invoke(null, "a", ImmutableList.of("b", "c")); 347 assertEquals(ImmutableList.of("a", "b", "c"), ImmutableList.copyOf(result)); 348 } 349 testStaticMethod_invalidReturning()350 public void testStaticMethod_invalidReturning() throws Exception { 351 Invokable<?, Object> delegate = Prepender.method("prepend", String.class, Iterable.class); 352 assertThrows( 353 IllegalArgumentException.class, 354 () -> delegate.returning(new TypeToken<Iterable<Integer>>() {})); 355 } 356 testInstanceMethod_returnType()357 public void testInstanceMethod_returnType() throws Exception { 358 Invokable<?, ?> delegate = Prepender.method("prepend", Iterable.class); 359 assertEquals(new TypeToken<Iterable<String>>() {}, delegate.getReturnType()); 360 } 361 testInstanceMethod_exceptionTypes()362 public void testInstanceMethod_exceptionTypes() throws Exception { 363 Invokable<?, ?> delegate = Prepender.method("prepend", Iterable.class); 364 assertEquals( 365 ImmutableList.of( 366 TypeToken.of(IllegalArgumentException.class), TypeToken.of(NullPointerException.class)), 367 delegate.getExceptionTypes()); 368 } 369 testInstanceMethod_typeParameters()370 public void testInstanceMethod_typeParameters() throws Exception { 371 Invokable<?, ?> delegate = Prepender.method("prepend", Iterable.class); 372 assertThat(delegate.getTypeParameters()).isEmpty(); 373 } 374 testInstanceMethod_parameters()375 public void testInstanceMethod_parameters() throws Exception { 376 Invokable<?, ?> delegate = Prepender.method("prepend", Iterable.class); 377 ImmutableList<Parameter> parameters = delegate.getParameters(); 378 assertEquals(1, parameters.size()); 379 assertEquals(new TypeToken<Iterable<String>>() {}, parameters.get(0).getType()); 380 assertThat(parameters.get(0).getAnnotations()).isEmpty(); 381 new EqualsTester().addEqualityGroup(parameters.get(0)).testEquals(); 382 } 383 testInstanceMethod_call()384 public void testInstanceMethod_call() throws Exception { 385 Invokable<Prepender, ?> delegate = Prepender.method("prepend", Iterable.class); 386 @SuppressWarnings("unchecked") // prepend() returns Iterable<String> 387 Iterable<String> result = 388 (Iterable<String>) delegate.invoke(new Prepender("a", 2), ImmutableList.of("b", "c")); 389 assertEquals(ImmutableList.of("a", "a", "b", "c"), ImmutableList.copyOf(result)); 390 } 391 testInstanceMethod_returning()392 public void testInstanceMethod_returning() throws Exception { 393 Invokable<Prepender, Iterable<String>> delegate = 394 Prepender.method("prepend", Iterable.class).returning(new TypeToken<Iterable<String>>() {}); 395 assertEquals(new TypeToken<Iterable<String>>() {}, delegate.getReturnType()); 396 Iterable<String> result = delegate.invoke(new Prepender("a", 2), ImmutableList.of("b", "c")); 397 assertEquals(ImmutableList.of("a", "a", "b", "c"), ImmutableList.copyOf(result)); 398 } 399 testInstanceMethod_returningRawType()400 public void testInstanceMethod_returningRawType() throws Exception { 401 @SuppressWarnings("rawtypes") // the purpose is to test raw type 402 Invokable<Prepender, Iterable> delegate = 403 Prepender.method("prepend", Iterable.class).returning(Iterable.class); 404 assertEquals(new TypeToken<Iterable<String>>() {}, delegate.getReturnType()); 405 @SuppressWarnings("unchecked") // prepend() returns Iterable<String> 406 Iterable<String> result = delegate.invoke(new Prepender("a", 2), ImmutableList.of("b", "c")); 407 assertEquals(ImmutableList.of("a", "a", "b", "c"), ImmutableList.copyOf(result)); 408 } 409 testInstanceMethod_invalidReturning()410 public void testInstanceMethod_invalidReturning() throws Exception { 411 Invokable<?, Object> delegate = Prepender.method("prepend", Iterable.class); 412 assertThrows( 413 IllegalArgumentException.class, 414 () -> delegate.returning(new TypeToken<Iterable<Integer>>() {})); 415 } 416 testPrivateInstanceMethod_isOverridable()417 public void testPrivateInstanceMethod_isOverridable() throws Exception { 418 Invokable<?, ?> delegate = Prepender.method("privateMethod"); 419 assertTrue(delegate.isPrivate()); 420 assertFalse(delegate.isOverridable()); 421 assertFalse(delegate.isVarArgs()); 422 } 423 testPrivateFinalInstanceMethod_isOverridable()424 public void testPrivateFinalInstanceMethod_isOverridable() throws Exception { 425 Invokable<?, ?> delegate = Prepender.method("privateFinalMethod"); 426 assertTrue(delegate.isPrivate()); 427 assertTrue(delegate.isFinal()); 428 assertFalse(delegate.isOverridable()); 429 assertFalse(delegate.isVarArgs()); 430 } 431 testStaticMethod_isOverridable()432 public void testStaticMethod_isOverridable() throws Exception { 433 Invokable<?, ?> delegate = Prepender.method("staticMethod"); 434 assertTrue(delegate.isStatic()); 435 assertFalse(delegate.isOverridable()); 436 assertFalse(delegate.isVarArgs()); 437 } 438 testStaticFinalMethod_isFinal()439 public void testStaticFinalMethod_isFinal() throws Exception { 440 Invokable<?, ?> delegate = Prepender.method("staticFinalMethod"); 441 assertTrue(delegate.isStatic()); 442 assertTrue(delegate.isFinal()); 443 assertFalse(delegate.isOverridable()); 444 assertFalse(delegate.isVarArgs()); 445 } 446 447 static class Foo {} 448 testConstructor_isOverridable()449 public void testConstructor_isOverridable() throws Exception { 450 Invokable<?, ?> delegate = Invokable.from(Foo.class.getDeclaredConstructor()); 451 assertFalse(delegate.isOverridable()); 452 assertFalse(delegate.isVarArgs()); 453 } 454 testMethod_isVarArgs()455 public void testMethod_isVarArgs() throws Exception { 456 Invokable<?, ?> delegate = Prepender.method("privateVarArgsMethod", String[].class); 457 assertTrue(delegate.isVarArgs()); 458 } 459 testConstructor_isVarArgs()460 public void testConstructor_isVarArgs() throws Exception { 461 Invokable<?, ?> delegate = Prepender.constructor(String[].class); 462 assertTrue(delegate.isVarArgs()); 463 } 464 testGetOwnerType_constructor()465 public void testGetOwnerType_constructor() throws Exception { 466 Invokable<String, String> invokable = Invokable.from(String.class.getConstructor()); 467 assertEquals(TypeToken.of(String.class), invokable.getOwnerType()); 468 } 469 testGetOwnerType_method()470 public void testGetOwnerType_method() throws Exception { 471 Invokable<?, ?> invokable = Invokable.from(String.class.getMethod("length")); 472 assertEquals(TypeToken.of(String.class), invokable.getOwnerType()); 473 } 474 475 private static final class FinalClass { 476 @SuppressWarnings("unused") // used by reflection notFinalMethod()477 void notFinalMethod() {} 478 } 479 testNonFinalMethodInFinalClass_isOverridable()480 public void testNonFinalMethodInFinalClass_isOverridable() throws Exception { 481 Invokable<?, ?> delegate = Invokable.from(FinalClass.class.getDeclaredMethod("notFinalMethod")); 482 assertFalse(delegate.isOverridable()); 483 assertFalse(delegate.isVarArgs()); 484 } 485 486 private class InnerWithDefaultConstructor { 487 class NestedInner {} 488 } 489 testInnerClassDefaultConstructor()490 public void testInnerClassDefaultConstructor() { 491 Constructor<?> constructor = InnerWithDefaultConstructor.class.getDeclaredConstructors()[0]; 492 assertEquals(0, Invokable.from(constructor).getParameters().size()); 493 } 494 testNestedInnerClassDefaultConstructor()495 public void testNestedInnerClassDefaultConstructor() { 496 Constructor<?> constructor = 497 InnerWithDefaultConstructor.NestedInner.class.getDeclaredConstructors()[0]; 498 assertEquals(0, Invokable.from(constructor).getParameters().size()); 499 } 500 501 private class InnerWithOneParameterConstructor { 502 @SuppressWarnings("unused") // called by reflection InnerWithOneParameterConstructor(String s)503 public InnerWithOneParameterConstructor(String s) {} 504 } 505 testInnerClassWithOneParameterConstructor()506 public void testInnerClassWithOneParameterConstructor() { 507 Constructor<?> constructor = 508 InnerWithOneParameterConstructor.class.getDeclaredConstructors()[0]; 509 Invokable<?, ?> invokable = Invokable.from(constructor); 510 assertEquals(1, invokable.getParameters().size()); 511 assertEquals(TypeToken.of(String.class), invokable.getParameters().get(0).getType()); 512 } 513 514 private class InnerWithAnnotatedConstructorParameter { 515 @SuppressWarnings("unused") // called by reflection InnerWithAnnotatedConstructorParameter(@ullable String s)516 InnerWithAnnotatedConstructorParameter(@Nullable String s) {} 517 } 518 testInnerClassWithAnnotatedConstructorParameter()519 public void testInnerClassWithAnnotatedConstructorParameter() { 520 Constructor<?> constructor = 521 InnerWithAnnotatedConstructorParameter.class.getDeclaredConstructors()[0]; 522 Invokable<?, ?> invokable = Invokable.from(constructor); 523 assertEquals(1, invokable.getParameters().size()); 524 assertEquals(TypeToken.of(String.class), invokable.getParameters().get(0).getType()); 525 } 526 527 private class InnerWithGenericConstructorParameter { 528 @SuppressWarnings("unused") // called by reflection InnerWithGenericConstructorParameter(Iterable<String> it, String s)529 InnerWithGenericConstructorParameter(Iterable<String> it, String s) {} 530 } 531 testInnerClassWithGenericConstructorParameter()532 public void testInnerClassWithGenericConstructorParameter() { 533 Constructor<?> constructor = 534 InnerWithGenericConstructorParameter.class.getDeclaredConstructors()[0]; 535 Invokable<?, ?> invokable = Invokable.from(constructor); 536 assertEquals(2, invokable.getParameters().size()); 537 assertEquals(new TypeToken<Iterable<String>>() {}, invokable.getParameters().get(0).getType()); 538 assertEquals(TypeToken.of(String.class), invokable.getParameters().get(1).getType()); 539 } 540 testAnonymousClassDefaultConstructor()541 public void testAnonymousClassDefaultConstructor() { 542 final int i = 1; 543 final String s = "hello world"; 544 Class<?> anonymous = 545 new Runnable() { 546 @Override 547 public void run() { 548 System.out.println(s + i); 549 } 550 }.getClass(); 551 Constructor<?> constructor = anonymous.getDeclaredConstructors()[0]; 552 assertEquals(0, Invokable.from(constructor).getParameters().size()); 553 } 554 testAnonymousClassWithTwoParametersConstructor()555 public void testAnonymousClassWithTwoParametersConstructor() { 556 abstract class Base { 557 @SuppressWarnings("unused") // called by reflection 558 Base(String s, int i) {} 559 } 560 Class<?> anonymous = new Base("test", 0) {}.getClass(); 561 Constructor<?> constructor = anonymous.getDeclaredConstructors()[0]; 562 assertEquals(2, Invokable.from(constructor).getParameters().size()); 563 } 564 testLocalClassDefaultConstructor()565 public void testLocalClassDefaultConstructor() { 566 final int i = 1; 567 final String s = "hello world"; 568 class LocalWithDefaultConstructor implements Runnable { 569 @Override 570 public void run() { 571 System.out.println(s + i); 572 } 573 } 574 Constructor<?> constructor = LocalWithDefaultConstructor.class.getDeclaredConstructors()[0]; 575 assertEquals(0, Invokable.from(constructor).getParameters().size()); 576 } 577 testStaticAnonymousClassDefaultConstructor()578 public void testStaticAnonymousClassDefaultConstructor() throws Exception { 579 doTestStaticAnonymousClassDefaultConstructor(); 580 } 581 doTestStaticAnonymousClassDefaultConstructor()582 private static void doTestStaticAnonymousClassDefaultConstructor() { 583 final int i = 1; 584 final String s = "hello world"; 585 Class<?> anonymous = 586 new Runnable() { 587 @Override 588 public void run() { 589 System.out.println(s + i); 590 } 591 }.getClass(); 592 Constructor<?> constructor = anonymous.getDeclaredConstructors()[0]; 593 assertEquals(0, Invokable.from(constructor).getParameters().size()); 594 } 595 testAnonymousClassInConstructor()596 public void testAnonymousClassInConstructor() { 597 AnonymousClassInConstructor unused = new AnonymousClassInConstructor(); 598 } 599 600 private static class AnonymousClassInConstructor { AnonymousClassInConstructor()601 AnonymousClassInConstructor() { 602 final int i = 1; 603 final String s = "hello world"; 604 Class<?> anonymous = 605 new Runnable() { 606 @Override 607 public void run() { 608 System.out.println(s + i); 609 } 610 }.getClass(); 611 Constructor<?> constructor = anonymous.getDeclaredConstructors()[0]; 612 assertEquals(0, Invokable.from(constructor).getParameters().size()); 613 } 614 } 615 testLocalClassInInstanceInitializer()616 public void testLocalClassInInstanceInitializer() { 617 LocalClassInInstanceInitializer unused = new LocalClassInInstanceInitializer(); 618 } 619 620 private static class LocalClassInInstanceInitializer { 621 { 622 class Local {} 623 Constructor<?> constructor = Local.class.getDeclaredConstructors()[0]; 624 assertEquals(0, Invokable.from(constructor).getParameters().size()); 625 } 626 } 627 testLocalClassInStaticInitializer()628 public void testLocalClassInStaticInitializer() { 629 LocalClassInStaticInitializer unused = new LocalClassInStaticInitializer(); 630 } 631 632 private static class LocalClassInStaticInitializer { 633 static { 634 class Local {} 635 Constructor<?> constructor = Local.class.getDeclaredConstructors()[0]; 636 assertEquals(0, Invokable.from(constructor).getParameters().size()); 637 } 638 } 639 testLocalClassWithSeeminglyHiddenThisInStaticInitializer_BUG()640 public void testLocalClassWithSeeminglyHiddenThisInStaticInitializer_BUG() { 641 LocalClassWithSeeminglyHiddenThisInStaticInitializer unused = 642 new LocalClassWithSeeminglyHiddenThisInStaticInitializer(); 643 } 644 645 /** 646 * This class demonstrates a bug in getParameters() when the local class is inside static 647 * initializer. 648 */ 649 private static class LocalClassWithSeeminglyHiddenThisInStaticInitializer { 650 static { 651 class Local { 652 @SuppressWarnings("unused") // through reflection Local(LocalClassWithSeeminglyHiddenThisInStaticInitializer outer)653 Local(LocalClassWithSeeminglyHiddenThisInStaticInitializer outer) {} 654 } 655 Constructor<?> constructor = Local.class.getDeclaredConstructors()[0]; 656 int miscalculated = 0; assertEquals(miscalculated, Invokable.from(constructor).getParameters().size())657 assertEquals(miscalculated, Invokable.from(constructor).getParameters().size()); 658 } 659 } 660 testLocalClassWithOneParameterConstructor()661 public void testLocalClassWithOneParameterConstructor() throws Exception { 662 final int i = 1; 663 final String s = "hello world"; 664 class LocalWithOneParameterConstructor { 665 @SuppressWarnings("unused") // called by reflection 666 public LocalWithOneParameterConstructor(String x) { 667 System.out.println(s + i); 668 } 669 } 670 Constructor<?> constructor = 671 LocalWithOneParameterConstructor.class.getDeclaredConstructors()[0]; 672 Invokable<?, ?> invokable = Invokable.from(constructor); 673 assertEquals(1, invokable.getParameters().size()); 674 assertEquals(TypeToken.of(String.class), invokable.getParameters().get(0).getType()); 675 } 676 testLocalClassWithAnnotatedConstructorParameter()677 public void testLocalClassWithAnnotatedConstructorParameter() throws Exception { 678 class LocalWithAnnotatedConstructorParameter { 679 @SuppressWarnings("unused") // called by reflection 680 LocalWithAnnotatedConstructorParameter(@Nullable String s) {} 681 } 682 Constructor<?> constructor = 683 LocalWithAnnotatedConstructorParameter.class.getDeclaredConstructors()[0]; 684 Invokable<?, ?> invokable = Invokable.from(constructor); 685 assertEquals(1, invokable.getParameters().size()); 686 assertEquals(TypeToken.of(String.class), invokable.getParameters().get(0).getType()); 687 } 688 testLocalClassWithGenericConstructorParameter()689 public void testLocalClassWithGenericConstructorParameter() throws Exception { 690 class LocalWithGenericConstructorParameter { 691 @SuppressWarnings("unused") // called by reflection 692 LocalWithGenericConstructorParameter(Iterable<String> it, String s) {} 693 } 694 Constructor<?> constructor = 695 LocalWithGenericConstructorParameter.class.getDeclaredConstructors()[0]; 696 Invokable<?, ?> invokable = Invokable.from(constructor); 697 assertEquals(2, invokable.getParameters().size()); 698 assertEquals(new TypeToken<Iterable<String>>() {}, invokable.getParameters().get(0).getType()); 699 assertEquals(TypeToken.of(String.class), invokable.getParameters().get(1).getType()); 700 } 701 testEquals()702 public void testEquals() throws Exception { 703 new EqualsTester() 704 .addEqualityGroup(A.constructor(), A.constructor()) 705 .addEqualityGroup(A.method("privateMethod"), A.method("privateMethod")) 706 .addEqualityGroup(A.method("publicFinalMethod")) 707 .addEqualityGroup(Prepender.constructor(), Prepender.constructor()) 708 .addEqualityGroup(Prepender.constructor(String.class, int.class)) 709 .addEqualityGroup(Prepender.method("privateMethod"), Prepender.method("privateMethod")) 710 .addEqualityGroup(Prepender.method("privateFinalMethod")) 711 .testEquals(); 712 } 713 testNulls()714 public void testNulls() { 715 new NullPointerTester().testAllPublicStaticMethods(Invokable.class); 716 new NullPointerTester().testAllPublicInstanceMethods(Prepender.method("staticMethod")); 717 } 718 719 @Retention(RetentionPolicy.RUNTIME) 720 private @interface NotBlank {} 721 722 /** Class for testing constructor, static method and instance method. */ 723 @SuppressWarnings("unused") // most are called by reflection 724 private static class Prepender { 725 726 private final String prefix; 727 private final int times; 728 Prepender(@otBlank @ullable String prefix, int times)729 Prepender(@NotBlank @Nullable String prefix, int times) throws NullPointerException { 730 this.prefix = prefix; 731 this.times = times; 732 } 733 Prepender(String... varargs)734 Prepender(String... varargs) { 735 this(null, 0); 736 } 737 738 // just for testing Prepender()739 private <T> Prepender() { 740 this(null, 0); 741 } 742 prepend(@otBlank String first, Iterable<String> tail)743 static <T> Iterable<String> prepend(@NotBlank String first, Iterable<String> tail) { 744 return Iterables.concat(ImmutableList.of(first), tail); 745 } 746 prepend(Iterable<String> tail)747 Iterable<String> prepend(Iterable<String> tail) 748 throws IllegalArgumentException, NullPointerException { 749 return Iterables.concat(Collections.nCopies(times, prefix), tail); 750 } 751 constructor(Class<?>.... parameterTypes)752 static Invokable<?, Prepender> constructor(Class<?>... parameterTypes) throws Exception { 753 Constructor<Prepender> constructor = Prepender.class.getDeclaredConstructor(parameterTypes); 754 return Invokable.from(constructor); 755 } 756 method(String name, Class<?>... parameterTypes)757 static Invokable<Prepender, Object> method(String name, Class<?>... parameterTypes) { 758 try { 759 Method method = Prepender.class.getDeclaredMethod(name, parameterTypes); 760 @SuppressWarnings("unchecked") // The method is from Prepender. 761 Invokable<Prepender, Object> invokable = 762 (Invokable<Prepender, Object>) Invokable.from(method); 763 return invokable; 764 } catch (NoSuchMethodException e) { 765 throw new IllegalArgumentException(e); 766 } 767 } 768 privateMethod()769 private void privateMethod() {} 770 privateFinalMethod()771 private final void privateFinalMethod() {} 772 staticMethod()773 static void staticMethod() {} 774 staticFinalMethod()775 static final void staticFinalMethod() {} 776 privateVarArgsMethod(String... varargs)777 private void privateVarArgsMethod(String... varargs) {} 778 } 779 780 private static class SubPrepender extends Prepender { 781 @SuppressWarnings("unused") // needed to satisfy compiler, never called SubPrepender()782 public SubPrepender() throws NullPointerException { 783 throw new AssertionError(); 784 } 785 } 786 } 787