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