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 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 assertThrows(IllegalArgumentException.class, () -> delegate.returning(SubPrepender.class)); 289 } 290 testStaticMethod_returnType()291 public void testStaticMethod_returnType() throws Exception { 292 Invokable<?, ?> delegate = Prepender.method("prepend", String.class, Iterable.class); 293 assertEquals(new TypeToken<Iterable<String>>() {}, delegate.getReturnType()); 294 } 295 testStaticMethod_exceptionTypes()296 public void testStaticMethod_exceptionTypes() throws Exception { 297 Invokable<?, ?> delegate = Prepender.method("prepend", String.class, Iterable.class); 298 assertEquals(ImmutableList.of(), delegate.getExceptionTypes()); 299 } 300 testStaticMethod_typeParameters()301 public void testStaticMethod_typeParameters() throws Exception { 302 Invokable<?, ?> delegate = Prepender.method("prepend", String.class, Iterable.class); 303 TypeVariable<?>[] variables = delegate.getTypeParameters(); 304 assertThat(variables).hasLength(1); 305 assertEquals("T", variables[0].getName()); 306 } 307 testStaticMethod_parameters()308 public void testStaticMethod_parameters() throws Exception { 309 Invokable<?, ?> delegate = Prepender.method("prepend", String.class, Iterable.class); 310 ImmutableList<Parameter> parameters = delegate.getParameters(); 311 assertEquals(2, parameters.size()); 312 assertEquals(String.class, parameters.get(0).getType().getType()); 313 assertTrue(parameters.get(0).isAnnotationPresent(NotBlank.class)); 314 assertEquals(new TypeToken<Iterable<String>>() {}, parameters.get(1).getType()); 315 assertFalse(parameters.get(1).isAnnotationPresent(NotBlank.class)); 316 new EqualsTester() 317 .addEqualityGroup(parameters.get(0)) 318 .addEqualityGroup(parameters.get(1)) 319 .testEquals(); 320 } 321 testStaticMethod_call()322 public void testStaticMethod_call() throws Exception { 323 Invokable<?, ?> delegate = Prepender.method("prepend", String.class, Iterable.class); 324 @SuppressWarnings("unchecked") // prepend() returns Iterable<String> 325 Iterable<String> result = 326 (Iterable<String>) delegate.invoke(null, "a", ImmutableList.of("b", "c")); 327 assertEquals(ImmutableList.of("a", "b", "c"), ImmutableList.copyOf(result)); 328 } 329 testStaticMethod_returning()330 public void testStaticMethod_returning() throws Exception { 331 Invokable<?, Iterable<String>> delegate = 332 Prepender.method("prepend", String.class, Iterable.class) 333 .returning(new TypeToken<Iterable<String>>() {}); 334 assertEquals(new TypeToken<Iterable<String>>() {}, delegate.getReturnType()); 335 Iterable<String> result = delegate.invoke(null, "a", ImmutableList.of("b", "c")); 336 assertEquals(ImmutableList.of("a", "b", "c"), ImmutableList.copyOf(result)); 337 } 338 testStaticMethod_returningRawType()339 public void testStaticMethod_returningRawType() throws Exception { 340 @SuppressWarnings("rawtypes") // the purpose is to test raw type 341 Invokable<?, Iterable> delegate = 342 Prepender.method("prepend", String.class, Iterable.class).returning(Iterable.class); 343 assertEquals(new TypeToken<Iterable<String>>() {}, delegate.getReturnType()); 344 @SuppressWarnings("unchecked") // prepend() returns Iterable<String> 345 Iterable<String> result = delegate.invoke(null, "a", ImmutableList.of("b", "c")); 346 assertEquals(ImmutableList.of("a", "b", "c"), ImmutableList.copyOf(result)); 347 } 348 testStaticMethod_invalidReturning()349 public void testStaticMethod_invalidReturning() throws Exception { 350 Invokable<?, Object> delegate = Prepender.method("prepend", String.class, Iterable.class); 351 assertThrows( 352 IllegalArgumentException.class, 353 () -> delegate.returning(new TypeToken<Iterable<Integer>>() {})); 354 } 355 testInstanceMethod_returnType()356 public void testInstanceMethod_returnType() throws Exception { 357 Invokable<?, ?> delegate = Prepender.method("prepend", Iterable.class); 358 assertEquals(new TypeToken<Iterable<String>>() {}, delegate.getReturnType()); 359 } 360 testInstanceMethod_exceptionTypes()361 public void testInstanceMethod_exceptionTypes() throws Exception { 362 Invokable<?, ?> delegate = Prepender.method("prepend", Iterable.class); 363 assertEquals( 364 ImmutableList.of( 365 TypeToken.of(IllegalArgumentException.class), TypeToken.of(NullPointerException.class)), 366 delegate.getExceptionTypes()); 367 } 368 testInstanceMethod_typeParameters()369 public void testInstanceMethod_typeParameters() throws Exception { 370 Invokable<?, ?> delegate = Prepender.method("prepend", Iterable.class); 371 assertThat(delegate.getTypeParameters()).isEmpty(); 372 } 373 testInstanceMethod_parameters()374 public void testInstanceMethod_parameters() throws Exception { 375 Invokable<?, ?> delegate = Prepender.method("prepend", Iterable.class); 376 ImmutableList<Parameter> parameters = delegate.getParameters(); 377 assertEquals(1, parameters.size()); 378 assertEquals(new TypeToken<Iterable<String>>() {}, parameters.get(0).getType()); 379 assertThat(parameters.get(0).getAnnotations()).isEmpty(); 380 new EqualsTester().addEqualityGroup(parameters.get(0)).testEquals(); 381 } 382 testInstanceMethod_call()383 public void testInstanceMethod_call() throws Exception { 384 Invokable<Prepender, ?> delegate = Prepender.method("prepend", Iterable.class); 385 @SuppressWarnings("unchecked") // prepend() returns Iterable<String> 386 Iterable<String> result = 387 (Iterable<String>) delegate.invoke(new Prepender("a", 2), ImmutableList.of("b", "c")); 388 assertEquals(ImmutableList.of("a", "a", "b", "c"), ImmutableList.copyOf(result)); 389 } 390 testInstanceMethod_returning()391 public void testInstanceMethod_returning() throws Exception { 392 Invokable<Prepender, Iterable<String>> delegate = 393 Prepender.method("prepend", Iterable.class).returning(new TypeToken<Iterable<String>>() {}); 394 assertEquals(new TypeToken<Iterable<String>>() {}, delegate.getReturnType()); 395 Iterable<String> result = delegate.invoke(new Prepender("a", 2), ImmutableList.of("b", "c")); 396 assertEquals(ImmutableList.of("a", "a", "b", "c"), ImmutableList.copyOf(result)); 397 } 398 testInstanceMethod_returningRawType()399 public void testInstanceMethod_returningRawType() throws Exception { 400 @SuppressWarnings("rawtypes") // the purpose is to test raw type 401 Invokable<Prepender, Iterable> delegate = 402 Prepender.method("prepend", Iterable.class).returning(Iterable.class); 403 assertEquals(new TypeToken<Iterable<String>>() {}, delegate.getReturnType()); 404 @SuppressWarnings("unchecked") // prepend() returns Iterable<String> 405 Iterable<String> result = delegate.invoke(new Prepender("a", 2), ImmutableList.of("b", "c")); 406 assertEquals(ImmutableList.of("a", "a", "b", "c"), ImmutableList.copyOf(result)); 407 } 408 testInstanceMethod_invalidReturning()409 public void testInstanceMethod_invalidReturning() throws Exception { 410 Invokable<?, Object> delegate = Prepender.method("prepend", Iterable.class); 411 assertThrows( 412 IllegalArgumentException.class, 413 () -> delegate.returning(new TypeToken<Iterable<Integer>>() {})); 414 } 415 testPrivateInstanceMethod_isOverridable()416 public void testPrivateInstanceMethod_isOverridable() throws Exception { 417 Invokable<?, ?> delegate = Prepender.method("privateMethod"); 418 assertTrue(delegate.isPrivate()); 419 assertFalse(delegate.isOverridable()); 420 assertFalse(delegate.isVarArgs()); 421 } 422 testPrivateFinalInstanceMethod_isOverridable()423 public void testPrivateFinalInstanceMethod_isOverridable() throws Exception { 424 Invokable<?, ?> delegate = Prepender.method("privateFinalMethod"); 425 assertTrue(delegate.isPrivate()); 426 assertTrue(delegate.isFinal()); 427 assertFalse(delegate.isOverridable()); 428 assertFalse(delegate.isVarArgs()); 429 } 430 testStaticMethod_isOverridable()431 public void testStaticMethod_isOverridable() throws Exception { 432 Invokable<?, ?> delegate = Prepender.method("staticMethod"); 433 assertTrue(delegate.isStatic()); 434 assertFalse(delegate.isOverridable()); 435 assertFalse(delegate.isVarArgs()); 436 } 437 testStaticFinalMethod_isFinal()438 public void testStaticFinalMethod_isFinal() throws Exception { 439 Invokable<?, ?> delegate = Prepender.method("staticFinalMethod"); 440 assertTrue(delegate.isStatic()); 441 assertTrue(delegate.isFinal()); 442 assertFalse(delegate.isOverridable()); 443 assertFalse(delegate.isVarArgs()); 444 } 445 446 static class Foo {} 447 testConstructor_isOverridable()448 public void testConstructor_isOverridable() throws Exception { 449 Invokable<?, ?> delegate = Invokable.from(Foo.class.getDeclaredConstructor()); 450 assertFalse(delegate.isOverridable()); 451 assertFalse(delegate.isVarArgs()); 452 } 453 testMethod_isVarArgs()454 public void testMethod_isVarArgs() throws Exception { 455 Invokable<?, ?> delegate = Prepender.method("privateVarArgsMethod", String[].class); 456 assertTrue(delegate.isVarArgs()); 457 } 458 testConstructor_isVarArgs()459 public void testConstructor_isVarArgs() throws Exception { 460 Invokable<?, ?> delegate = Prepender.constructor(String[].class); 461 assertTrue(delegate.isVarArgs()); 462 } 463 testGetOwnerType_constructor()464 public void testGetOwnerType_constructor() throws Exception { 465 Invokable<String, String> invokable = Invokable.from(String.class.getConstructor()); 466 assertEquals(TypeToken.of(String.class), invokable.getOwnerType()); 467 } 468 testGetOwnerType_method()469 public void testGetOwnerType_method() throws Exception { 470 Invokable<?, ?> invokable = Invokable.from(String.class.getMethod("length")); 471 assertEquals(TypeToken.of(String.class), invokable.getOwnerType()); 472 } 473 474 private static final class FinalClass { 475 @SuppressWarnings("unused") // used by reflection notFinalMethod()476 void notFinalMethod() {} 477 } 478 testNonFinalMethodInFinalClass_isOverridable()479 public void testNonFinalMethodInFinalClass_isOverridable() throws Exception { 480 Invokable<?, ?> delegate = Invokable.from(FinalClass.class.getDeclaredMethod("notFinalMethod")); 481 assertFalse(delegate.isOverridable()); 482 assertFalse(delegate.isVarArgs()); 483 } 484 485 private class InnerWithDefaultConstructor { 486 class NestedInner {} 487 } 488 testInnerClassDefaultConstructor()489 public void testInnerClassDefaultConstructor() { 490 Constructor<?> constructor = InnerWithDefaultConstructor.class.getDeclaredConstructors()[0]; 491 assertEquals(0, Invokable.from(constructor).getParameters().size()); 492 } 493 testNestedInnerClassDefaultConstructor()494 public void testNestedInnerClassDefaultConstructor() { 495 Constructor<?> constructor = 496 InnerWithDefaultConstructor.NestedInner.class.getDeclaredConstructors()[0]; 497 assertEquals(0, Invokable.from(constructor).getParameters().size()); 498 } 499 500 private class InnerWithOneParameterConstructor { 501 @SuppressWarnings("unused") // called by reflection InnerWithOneParameterConstructor(String s)502 public InnerWithOneParameterConstructor(String s) {} 503 } 504 testInnerClassWithOneParameterConstructor()505 public void testInnerClassWithOneParameterConstructor() { 506 Constructor<?> constructor = 507 InnerWithOneParameterConstructor.class.getDeclaredConstructors()[0]; 508 Invokable<?, ?> invokable = Invokable.from(constructor); 509 assertEquals(1, invokable.getParameters().size()); 510 assertEquals(TypeToken.of(String.class), invokable.getParameters().get(0).getType()); 511 } 512 513 private class InnerWithAnnotatedConstructorParameter { 514 @SuppressWarnings("unused") // called by reflection InnerWithAnnotatedConstructorParameter(@ullable String s)515 InnerWithAnnotatedConstructorParameter(@Nullable String s) {} 516 } 517 testInnerClassWithAnnotatedConstructorParameter()518 public void testInnerClassWithAnnotatedConstructorParameter() { 519 Constructor<?> constructor = 520 InnerWithAnnotatedConstructorParameter.class.getDeclaredConstructors()[0]; 521 Invokable<?, ?> invokable = Invokable.from(constructor); 522 assertEquals(1, invokable.getParameters().size()); 523 assertEquals(TypeToken.of(String.class), invokable.getParameters().get(0).getType()); 524 } 525 526 private class InnerWithGenericConstructorParameter { 527 @SuppressWarnings("unused") // called by reflection InnerWithGenericConstructorParameter(Iterable<String> it, String s)528 InnerWithGenericConstructorParameter(Iterable<String> it, String s) {} 529 } 530 testInnerClassWithGenericConstructorParameter()531 public void testInnerClassWithGenericConstructorParameter() { 532 Constructor<?> constructor = 533 InnerWithGenericConstructorParameter.class.getDeclaredConstructors()[0]; 534 Invokable<?, ?> invokable = Invokable.from(constructor); 535 assertEquals(2, invokable.getParameters().size()); 536 assertEquals(new TypeToken<Iterable<String>>() {}, invokable.getParameters().get(0).getType()); 537 assertEquals(TypeToken.of(String.class), invokable.getParameters().get(1).getType()); 538 } 539 testAnonymousClassDefaultConstructor()540 public void testAnonymousClassDefaultConstructor() { 541 final int i = 1; 542 final String s = "hello world"; 543 Class<?> anonymous = 544 new Runnable() { 545 @Override 546 public void run() { 547 System.out.println(s + i); 548 } 549 }.getClass(); 550 Constructor<?> constructor = anonymous.getDeclaredConstructors()[0]; 551 assertEquals(0, Invokable.from(constructor).getParameters().size()); 552 } 553 testAnonymousClassWithTwoParametersConstructor()554 public void testAnonymousClassWithTwoParametersConstructor() { 555 abstract class Base { 556 @SuppressWarnings("unused") // called by reflection 557 Base(String s, int i) {} 558 } 559 Class<?> anonymous = new Base("test", 0) {}.getClass(); 560 Constructor<?> constructor = anonymous.getDeclaredConstructors()[0]; 561 assertEquals(2, Invokable.from(constructor).getParameters().size()); 562 } 563 testLocalClassDefaultConstructor()564 public void testLocalClassDefaultConstructor() { 565 final int i = 1; 566 final String s = "hello world"; 567 class LocalWithDefaultConstructor implements Runnable { 568 @Override 569 public void run() { 570 System.out.println(s + i); 571 } 572 } 573 Constructor<?> constructor = LocalWithDefaultConstructor.class.getDeclaredConstructors()[0]; 574 assertEquals(0, Invokable.from(constructor).getParameters().size()); 575 } 576 testStaticAnonymousClassDefaultConstructor()577 public void testStaticAnonymousClassDefaultConstructor() throws Exception { 578 doTestStaticAnonymousClassDefaultConstructor(); 579 } 580 doTestStaticAnonymousClassDefaultConstructor()581 private static void doTestStaticAnonymousClassDefaultConstructor() { 582 final int i = 1; 583 final String s = "hello world"; 584 Class<?> anonymous = 585 new Runnable() { 586 @Override 587 public void run() { 588 System.out.println(s + i); 589 } 590 }.getClass(); 591 Constructor<?> constructor = anonymous.getDeclaredConstructors()[0]; 592 assertEquals(0, Invokable.from(constructor).getParameters().size()); 593 } 594 testAnonymousClassInConstructor()595 public void testAnonymousClassInConstructor() { 596 AnonymousClassInConstructor unused = new AnonymousClassInConstructor(); 597 } 598 599 private static class AnonymousClassInConstructor { AnonymousClassInConstructor()600 AnonymousClassInConstructor() { 601 final int i = 1; 602 final String s = "hello world"; 603 Class<?> anonymous = 604 new Runnable() { 605 @Override 606 public void run() { 607 System.out.println(s + i); 608 } 609 }.getClass(); 610 Constructor<?> constructor = anonymous.getDeclaredConstructors()[0]; 611 assertEquals(0, Invokable.from(constructor).getParameters().size()); 612 } 613 } 614 testLocalClassInInstanceInitializer()615 public void testLocalClassInInstanceInitializer() { 616 LocalClassInInstanceInitializer unused = new LocalClassInInstanceInitializer(); 617 } 618 619 private static class LocalClassInInstanceInitializer { 620 { 621 class Local {} 622 Constructor<?> constructor = Local.class.getDeclaredConstructors()[0]; 623 assertEquals(0, Invokable.from(constructor).getParameters().size()); 624 } 625 } 626 testLocalClassInStaticInitializer()627 public void testLocalClassInStaticInitializer() { 628 LocalClassInStaticInitializer unused = new LocalClassInStaticInitializer(); 629 } 630 631 private static class LocalClassInStaticInitializer { 632 static { 633 class Local {} 634 Constructor<?> constructor = Local.class.getDeclaredConstructors()[0]; 635 assertEquals(0, Invokable.from(constructor).getParameters().size()); 636 } 637 } 638 testLocalClassWithSeeminglyHiddenThisInStaticInitializer_bug()639 public void testLocalClassWithSeeminglyHiddenThisInStaticInitializer_bug() { 640 LocalClassWithSeeminglyHiddenThisInStaticInitializer unused = 641 new LocalClassWithSeeminglyHiddenThisInStaticInitializer(); 642 } 643 644 /** 645 * This class demonstrates a bug in getParameters() when the local class is inside static 646 * initializer. 647 */ 648 private static class LocalClassWithSeeminglyHiddenThisInStaticInitializer { 649 static { 650 class Local { 651 @SuppressWarnings("unused") // through reflection Local(LocalClassWithSeeminglyHiddenThisInStaticInitializer outer)652 Local(LocalClassWithSeeminglyHiddenThisInStaticInitializer outer) {} 653 } 654 Constructor<?> constructor = Local.class.getDeclaredConstructors()[0]; 655 int miscalculated = 0; assertEquals(miscalculated, Invokable.from(constructor).getParameters().size())656 assertEquals(miscalculated, Invokable.from(constructor).getParameters().size()); 657 } 658 } 659 testLocalClassWithOneParameterConstructor()660 public void testLocalClassWithOneParameterConstructor() throws Exception { 661 final int i = 1; 662 final String s = "hello world"; 663 class LocalWithOneParameterConstructor { 664 @SuppressWarnings("unused") // called by reflection 665 public LocalWithOneParameterConstructor(String x) { 666 System.out.println(s + i); 667 } 668 } 669 Constructor<?> constructor = 670 LocalWithOneParameterConstructor.class.getDeclaredConstructors()[0]; 671 Invokable<?, ?> invokable = Invokable.from(constructor); 672 assertEquals(1, invokable.getParameters().size()); 673 assertEquals(TypeToken.of(String.class), invokable.getParameters().get(0).getType()); 674 } 675 testLocalClassWithAnnotatedConstructorParameter()676 public void testLocalClassWithAnnotatedConstructorParameter() throws Exception { 677 class LocalWithAnnotatedConstructorParameter { 678 @SuppressWarnings("unused") // called by reflection 679 LocalWithAnnotatedConstructorParameter(@Nullable String s) {} 680 } 681 Constructor<?> constructor = 682 LocalWithAnnotatedConstructorParameter.class.getDeclaredConstructors()[0]; 683 Invokable<?, ?> invokable = Invokable.from(constructor); 684 assertEquals(1, invokable.getParameters().size()); 685 assertEquals(TypeToken.of(String.class), invokable.getParameters().get(0).getType()); 686 } 687 testLocalClassWithGenericConstructorParameter()688 public void testLocalClassWithGenericConstructorParameter() throws Exception { 689 class LocalWithGenericConstructorParameter { 690 @SuppressWarnings("unused") // called by reflection 691 LocalWithGenericConstructorParameter(Iterable<String> it, String s) {} 692 } 693 Constructor<?> constructor = 694 LocalWithGenericConstructorParameter.class.getDeclaredConstructors()[0]; 695 Invokable<?, ?> invokable = Invokable.from(constructor); 696 assertEquals(2, invokable.getParameters().size()); 697 assertEquals(new TypeToken<Iterable<String>>() {}, invokable.getParameters().get(0).getType()); 698 assertEquals(TypeToken.of(String.class), invokable.getParameters().get(1).getType()); 699 } 700 testEquals()701 public void testEquals() throws Exception { 702 new EqualsTester() 703 .addEqualityGroup(A.constructor(), A.constructor()) 704 .addEqualityGroup(A.method("privateMethod"), A.method("privateMethod")) 705 .addEqualityGroup(A.method("publicFinalMethod")) 706 .addEqualityGroup(Prepender.constructor(), Prepender.constructor()) 707 .addEqualityGroup(Prepender.constructor(String.class, int.class)) 708 .addEqualityGroup(Prepender.method("privateMethod"), Prepender.method("privateMethod")) 709 .addEqualityGroup(Prepender.method("privateFinalMethod")) 710 .testEquals(); 711 } 712 testNulls()713 public void testNulls() { 714 new NullPointerTester().testAllPublicStaticMethods(Invokable.class); 715 new NullPointerTester().testAllPublicInstanceMethods(Prepender.method("staticMethod")); 716 } 717 718 @Retention(RetentionPolicy.RUNTIME) 719 private @interface NotBlank {} 720 721 /** Class for testing constructor, static method and instance method. */ 722 @SuppressWarnings("unused") // most are called by reflection 723 private static class Prepender { 724 725 private final String prefix; 726 private final int times; 727 Prepender(@otBlank @ullable String prefix, int times)728 Prepender(@NotBlank @Nullable String prefix, int times) throws NullPointerException { 729 this.prefix = prefix; 730 this.times = times; 731 } 732 Prepender(String... varargs)733 Prepender(String... varargs) { 734 this(null, 0); 735 } 736 737 // just for testing Prepender()738 private <T> Prepender() { 739 this(null, 0); 740 } 741 prepend(@otBlank String first, Iterable<String> tail)742 static <T> Iterable<String> prepend(@NotBlank String first, Iterable<String> tail) { 743 return Iterables.concat(ImmutableList.of(first), tail); 744 } 745 prepend(Iterable<String> tail)746 Iterable<String> prepend(Iterable<String> tail) 747 throws IllegalArgumentException, NullPointerException { 748 return Iterables.concat(Collections.nCopies(times, prefix), tail); 749 } 750 constructor(Class<?>.... parameterTypes)751 static Invokable<?, Prepender> constructor(Class<?>... parameterTypes) throws Exception { 752 Constructor<Prepender> constructor = Prepender.class.getDeclaredConstructor(parameterTypes); 753 return Invokable.from(constructor); 754 } 755 method(String name, Class<?>... parameterTypes)756 static Invokable<Prepender, Object> method(String name, Class<?>... parameterTypes) { 757 try { 758 Method method = Prepender.class.getDeclaredMethod(name, parameterTypes); 759 @SuppressWarnings("unchecked") // The method is from Prepender. 760 Invokable<Prepender, Object> invokable = 761 (Invokable<Prepender, Object>) Invokable.from(method); 762 return invokable; 763 } catch (NoSuchMethodException e) { 764 throw new IllegalArgumentException(e); 765 } 766 } 767 privateMethod()768 private void privateMethod() {} 769 privateFinalMethod()770 private final void privateFinalMethod() {} 771 staticMethod()772 static void staticMethod() {} 773 staticFinalMethod()774 static final void staticFinalMethod() {} 775 privateVarArgsMethod(String... varargs)776 private void privateVarArgsMethod(String... varargs) {} 777 } 778 779 private static class SubPrepender extends Prepender { 780 @SuppressWarnings("unused") // needed to satisfy compiler, never called SubPrepender()781 public SubPrepender() throws NullPointerException { 782 throw new AssertionError(); 783 } 784 } 785 } 786