001/* 002 * Copyright (C) 2012 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 005 * in compliance with the License. You may obtain a copy of the License at 006 * 007 * http://www.apache.org/licenses/LICENSE-2.0 008 * 009 * Unless required by applicable law or agreed to in writing, software distributed under the License 010 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 011 * or implied. See the License for the specific language governing permissions and limitations under 012 * the License. 013 */ 014 015package com.google.common.reflect; 016 017import static com.google.common.base.Preconditions.checkNotNull; 018 019import com.google.common.annotations.Beta; 020import com.google.common.collect.ImmutableList; 021import com.google.errorprone.annotations.CanIgnoreReturnValue; 022import com.google.errorprone.annotations.DoNotCall; 023import java.lang.annotation.Annotation; 024import java.lang.reflect.AccessibleObject; 025import java.lang.reflect.AnnotatedElement; 026import java.lang.reflect.AnnotatedType; 027import java.lang.reflect.Constructor; 028import java.lang.reflect.InvocationTargetException; 029import java.lang.reflect.Member; 030import java.lang.reflect.Method; 031import java.lang.reflect.Modifier; 032import java.lang.reflect.Type; 033import java.lang.reflect.TypeVariable; 034import java.util.Arrays; 035import javax.annotation.CheckForNull; 036import org.checkerframework.checker.nullness.qual.Nullable; 037 038/** 039 * Wrapper around either a {@link Method} or a {@link Constructor}. Convenience API is provided to 040 * make common reflective operation easier to deal with, such as {@link #isPublic}, {@link 041 * #getParameters} etc. 042 * 043 * <p>In addition to convenience methods, {@link TypeToken#method} and {@link TypeToken#constructor} 044 * will resolve the type parameters of the method or constructor in the context of the owner type, 045 * which may be a subtype of the declaring class. For example: 046 * 047 * <pre>{@code 048 * Method getMethod = List.class.getMethod("get", int.class); 049 * Invokable<List<String>, ?> invokable = new TypeToken<List<String>>() {}.method(getMethod); 050 * assertEquals(TypeToken.of(String.class), invokable.getReturnType()); // Not Object.class! 051 * assertEquals(new TypeToken<List<String>>() {}, invokable.getOwnerType()); 052 * }</pre> 053 * 054 * <p><b>Note:</b> earlier versions of this class inherited from {@link 055 * java.lang.reflect.AccessibleObject AccessibleObject} and {@link 056 * java.lang.reflect.GenericDeclaration GenericDeclaration}. Since version 31.0 that is no longer 057 * the case. However, most methods from those types are present with the same signature in this 058 * class. 059 * 060 * @param <T> the type that owns this method or constructor. 061 * @param <R> the return type of (or supertype thereof) the method or the declaring type of the 062 * constructor. 063 * @author Ben Yu 064 * @since 14.0 (no longer implements {@link AccessibleObject} or {@code GenericDeclaration} since 065 * 31.0) 066 */ 067@ElementTypesAreNonnullByDefault 068public abstract class Invokable<T, R> implements AnnotatedElement, Member { 069 private final AccessibleObject accessibleObject; 070 private final Member member; 071 072 <M extends AccessibleObject & Member> Invokable(M member) { 073 checkNotNull(member); 074 this.accessibleObject = member; 075 this.member = member; 076 } 077 078 /** Returns {@link Invokable} of {@code method}. */ 079 public static Invokable<?, Object> from(Method method) { 080 return new MethodInvokable<>(method); 081 } 082 083 /** Returns {@link Invokable} of {@code constructor}. */ 084 public static <T> Invokable<T, T> from(Constructor<T> constructor) { 085 return new ConstructorInvokable<T>(constructor); 086 } 087 088 @Override 089 public final boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) { 090 return accessibleObject.isAnnotationPresent(annotationClass); 091 } 092 093 @Override 094 @CheckForNull 095 public final <A extends Annotation> A getAnnotation(Class<A> annotationClass) { 096 return accessibleObject.getAnnotation(annotationClass); 097 } 098 099 @Override 100 public final Annotation[] getAnnotations() { 101 return accessibleObject.getAnnotations(); 102 } 103 104 @Override 105 public final Annotation[] getDeclaredAnnotations() { 106 return accessibleObject.getDeclaredAnnotations(); 107 } 108 109 // We ought to be able to implement GenericDeclaration instead its parent AnnotatedElement. 110 // That would give us this method declaration. But for some reason, implementing 111 // GenericDeclaration leads to weird errors in Android tests: 112 // IncompatibleClassChangeError: interface not implemented 113 /** See {@link java.lang.reflect.GenericDeclaration#getTypeParameters()}. */ 114 public abstract TypeVariable<?>[] getTypeParameters(); 115 116 /** See {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)}. */ 117 public final void setAccessible(boolean flag) { 118 accessibleObject.setAccessible(flag); 119 } 120 121 /** See {@link java.lang.reflect.AccessibleObject#trySetAccessible()}. */ 122 public final boolean trySetAccessible() { 123 // We can't call accessibleObject.trySetAccessible since that was added in Java 9 and this code 124 // should work on Java 8. So we emulate it this way. 125 try { 126 accessibleObject.setAccessible(true); 127 return true; 128 } catch (RuntimeException e) { 129 return false; 130 } 131 } 132 133 /** See {@link java.lang.reflect.AccessibleObject#isAccessible()}. */ 134 public final boolean isAccessible() { 135 return accessibleObject.isAccessible(); 136 } 137 138 @Override 139 public final String getName() { 140 return member.getName(); 141 } 142 143 @Override 144 public final int getModifiers() { 145 return member.getModifiers(); 146 } 147 148 @Override 149 public final boolean isSynthetic() { 150 return member.isSynthetic(); 151 } 152 153 /** Returns true if the element is public. */ 154 public final boolean isPublic() { 155 return Modifier.isPublic(getModifiers()); 156 } 157 158 /** Returns true if the element is protected. */ 159 public final boolean isProtected() { 160 return Modifier.isProtected(getModifiers()); 161 } 162 163 /** Returns true if the element is package-private. */ 164 public final boolean isPackagePrivate() { 165 return !isPrivate() && !isPublic() && !isProtected(); 166 } 167 168 /** Returns true if the element is private. */ 169 public final boolean isPrivate() { 170 return Modifier.isPrivate(getModifiers()); 171 } 172 173 /** Returns true if the element is static. */ 174 public final boolean isStatic() { 175 return Modifier.isStatic(getModifiers()); 176 } 177 178 /** 179 * Returns {@code true} if this method is final, per {@code Modifier.isFinal(getModifiers())}. 180 * 181 * <p>Note that a method may still be effectively "final", or non-overridable when it has no 182 * {@code final} keyword. For example, it could be private, or it could be declared by a final 183 * class. To tell whether a method is overridable, use {@link Invokable#isOverridable}. 184 */ 185 public final boolean isFinal() { 186 return Modifier.isFinal(getModifiers()); 187 } 188 189 /** Returns true if the method is abstract. */ 190 public final boolean isAbstract() { 191 return Modifier.isAbstract(getModifiers()); 192 } 193 194 /** Returns true if the element is native. */ 195 public final boolean isNative() { 196 return Modifier.isNative(getModifiers()); 197 } 198 199 /** Returns true if the method is synchronized. */ 200 public final boolean isSynchronized() { 201 return Modifier.isSynchronized(getModifiers()); 202 } 203 204 /** Returns true if the field is volatile. */ 205 final boolean isVolatile() { 206 return Modifier.isVolatile(getModifiers()); 207 } 208 209 /** Returns true if the field is transient. */ 210 final boolean isTransient() { 211 return Modifier.isTransient(getModifiers()); 212 } 213 214 @Override 215 public boolean equals(@CheckForNull Object obj) { 216 if (obj instanceof Invokable) { 217 Invokable<?, ?> that = (Invokable<?, ?>) obj; 218 return getOwnerType().equals(that.getOwnerType()) && member.equals(that.member); 219 } 220 return false; 221 } 222 223 @Override 224 public int hashCode() { 225 return member.hashCode(); 226 } 227 228 @Override 229 public String toString() { 230 return member.toString(); 231 } 232 233 /** 234 * Returns {@code true} if this is an overridable method. Constructors, private, static or final 235 * methods, or methods declared by final classes are not overridable. 236 */ 237 public abstract boolean isOverridable(); 238 239 /** Returns {@code true} if this was declared to take a variable number of arguments. */ 240 public abstract boolean isVarArgs(); 241 242 /** 243 * Invokes with {@code receiver} as 'this' and {@code args} passed to the underlying method and 244 * returns the return value; or calls the underlying constructor with {@code args} and returns the 245 * constructed instance. 246 * 247 * @throws IllegalAccessException if this {@code Constructor} object enforces Java language access 248 * control and the underlying method or constructor is inaccessible. 249 * @throws IllegalArgumentException if the number of actual and formal parameters differ; if an 250 * unwrapping conversion for primitive arguments fails; or if, after possible unwrapping, a 251 * parameter value cannot be converted to the corresponding formal parameter type by a method 252 * invocation conversion. 253 * @throws InvocationTargetException if the underlying method or constructor throws an exception. 254 */ 255 // All subclasses are owned by us and we'll make sure to get the R type right, including nullness. 256 @SuppressWarnings({"unchecked", "nullness"}) 257 @CanIgnoreReturnValue 258 @CheckForNull 259 public final R invoke(@CheckForNull T receiver, @Nullable Object... args) 260 throws InvocationTargetException, IllegalAccessException { 261 return (R) invokeInternal(receiver, checkNotNull(args)); 262 } 263 264 /** Returns the return type of this {@code Invokable}. */ 265 // All subclasses are owned by us and we'll make sure to get the R type right. 266 @SuppressWarnings("unchecked") 267 public final TypeToken<? extends R> getReturnType() { 268 return (TypeToken<? extends R>) TypeToken.of(getGenericReturnType()); 269 } 270 271 /** 272 * Returns all declared parameters of this {@code Invokable}. Note that if this is a constructor 273 * of a non-static inner class, unlike {@link Constructor#getParameterTypes}, the hidden {@code 274 * this} parameter of the enclosing class is excluded from the returned parameters. 275 */ 276 @IgnoreJRERequirement 277 public final ImmutableList<Parameter> getParameters() { 278 Type[] parameterTypes = getGenericParameterTypes(); 279 Annotation[][] annotations = getParameterAnnotations(); 280 @Nullable Object[] annotatedTypes = 281 ANNOTATED_TYPE_EXISTS ? getAnnotatedParameterTypes() : new Object[parameterTypes.length]; 282 ImmutableList.Builder<Parameter> builder = ImmutableList.builder(); 283 for (int i = 0; i < parameterTypes.length; i++) { 284 builder.add( 285 new Parameter( 286 this, i, TypeToken.of(parameterTypes[i]), annotations[i], annotatedTypes[i])); 287 } 288 return builder.build(); 289 } 290 291 /** Returns all declared exception types of this {@code Invokable}. */ 292 public final ImmutableList<TypeToken<? extends Throwable>> getExceptionTypes() { 293 ImmutableList.Builder<TypeToken<? extends Throwable>> builder = ImmutableList.builder(); 294 for (Type type : getGenericExceptionTypes()) { 295 // getGenericExceptionTypes() will never return a type that's not exception 296 @SuppressWarnings("unchecked") 297 TypeToken<? extends Throwable> exceptionType = 298 (TypeToken<? extends Throwable>) TypeToken.of(type); 299 builder.add(exceptionType); 300 } 301 return builder.build(); 302 } 303 304 /** 305 * Explicitly specifies the return type of this {@code Invokable}. For example: 306 * 307 * <pre>{@code 308 * Method factoryMethod = Person.class.getMethod("create"); 309 * Invokable<?, Person> factory = Invokable.of(getNameMethod).returning(Person.class); 310 * }</pre> 311 */ 312 public final <R1 extends R> Invokable<T, R1> returning(Class<R1> returnType) { 313 return returning(TypeToken.of(returnType)); 314 } 315 316 /** Explicitly specifies the return type of this {@code Invokable}. */ 317 public final <R1 extends R> Invokable<T, R1> returning(TypeToken<R1> returnType) { 318 if (!returnType.isSupertypeOf(getReturnType())) { 319 throw new IllegalArgumentException( 320 "Invokable is known to return " + getReturnType() + ", not " + returnType); 321 } 322 @SuppressWarnings("unchecked") // guarded by previous check 323 Invokable<T, R1> specialized = (Invokable<T, R1>) this; 324 return specialized; 325 } 326 327 @SuppressWarnings("unchecked") // The declaring class is T's raw class, or one of its supertypes. 328 @Override 329 public final Class<? super T> getDeclaringClass() { 330 return (Class<? super T>) member.getDeclaringClass(); 331 } 332 333 /** Returns the type of {@code T}. */ 334 // Overridden in TypeToken#method() and TypeToken#constructor() 335 @SuppressWarnings("unchecked") // The declaring class is T. 336 public TypeToken<T> getOwnerType() { 337 return (TypeToken<T>) TypeToken.of(getDeclaringClass()); 338 } 339 340 @CheckForNull 341 abstract Object invokeInternal(@CheckForNull Object receiver, @Nullable Object[] args) 342 throws InvocationTargetException, IllegalAccessException; 343 344 abstract Type[] getGenericParameterTypes(); 345 346 @SuppressWarnings({"Java7ApiChecker", "AndroidJdkLibsChecker"}) 347 @IgnoreJRERequirement 348 abstract AnnotatedType[] getAnnotatedParameterTypes(); 349 350 /** This should never return a type that's not a subtype of Throwable. */ 351 abstract Type[] getGenericExceptionTypes(); 352 353 abstract Annotation[][] getParameterAnnotations(); 354 355 abstract Type getGenericReturnType(); 356 357 /** 358 * Returns the {@link AnnotatedType} for the return type. 359 * 360 * <p>This method will fail if run under an Android VM. 361 * 362 * @since NEXT for guava-android (available since 14.0 in guava-jre) 363 * @deprecated This method does not work under Android VMs. It is safe to use from guava-jre, but 364 * this copy in guava-android is not safe to use. 365 */ 366 @SuppressWarnings({"Java7ApiChecker", "AndroidJdkLibsChecker"}) 367 @DoNotCall("fails under Android VMs; do not use from guava-android") 368 @Deprecated 369 @IgnoreJRERequirement 370 @Beta 371 public abstract AnnotatedType getAnnotatedReturnType(); 372 373 static class MethodInvokable<T> extends Invokable<T, Object> { 374 375 final Method method; 376 377 MethodInvokable(Method method) { 378 super(method); 379 this.method = method; 380 } 381 382 @Override 383 @CheckForNull 384 final Object invokeInternal(@CheckForNull Object receiver, @Nullable Object[] args) 385 throws InvocationTargetException, IllegalAccessException { 386 return method.invoke(receiver, args); 387 } 388 389 @Override 390 Type getGenericReturnType() { 391 return method.getGenericReturnType(); 392 } 393 394 @Override 395 Type[] getGenericParameterTypes() { 396 return method.getGenericParameterTypes(); 397 } 398 399 @Override 400 @SuppressWarnings({"Java7ApiChecker", "AndroidJdkLibsChecker"}) 401 @IgnoreJRERequirement 402 AnnotatedType[] getAnnotatedParameterTypes() { 403 return method.getAnnotatedParameterTypes(); 404 } 405 406 @Override 407 @SuppressWarnings({"Java7ApiChecker", "AndroidJdkLibsChecker", "DoNotCall"}) 408 @DoNotCall 409 @IgnoreJRERequirement 410 public AnnotatedType getAnnotatedReturnType() { 411 return method.getAnnotatedReturnType(); 412 } 413 414 @Override 415 Type[] getGenericExceptionTypes() { 416 return method.getGenericExceptionTypes(); 417 } 418 419 @Override 420 final Annotation[][] getParameterAnnotations() { 421 return method.getParameterAnnotations(); 422 } 423 424 @Override 425 public final TypeVariable<?>[] getTypeParameters() { 426 return method.getTypeParameters(); 427 } 428 429 @Override 430 public final boolean isOverridable() { 431 return !(isFinal() 432 || isPrivate() 433 || isStatic() 434 || Modifier.isFinal(getDeclaringClass().getModifiers())); 435 } 436 437 @Override 438 public final boolean isVarArgs() { 439 return method.isVarArgs(); 440 } 441 } 442 443 static class ConstructorInvokable<T> extends Invokable<T, T> { 444 445 final Constructor<?> constructor; 446 447 ConstructorInvokable(Constructor<?> constructor) { 448 super(constructor); 449 this.constructor = constructor; 450 } 451 452 @Override 453 final Object invokeInternal(@CheckForNull Object receiver, @Nullable Object[] args) 454 throws InvocationTargetException, IllegalAccessException { 455 try { 456 return constructor.newInstance(args); 457 } catch (InstantiationException e) { 458 throw new RuntimeException(constructor + " failed.", e); 459 } 460 } 461 462 /** 463 * If the class is parameterized, such as {@link java.util.ArrayList ArrayList}, this returns 464 * {@code ArrayList<E>}. 465 */ 466 @Override 467 Type getGenericReturnType() { 468 Class<?> declaringClass = getDeclaringClass(); 469 TypeVariable<?>[] typeParams = declaringClass.getTypeParameters(); 470 if (typeParams.length > 0) { 471 return Types.newParameterizedType(declaringClass, typeParams); 472 } else { 473 return declaringClass; 474 } 475 } 476 477 @Override 478 Type[] getGenericParameterTypes() { 479 Type[] types = constructor.getGenericParameterTypes(); 480 if (types.length > 0 && mayNeedHiddenThis()) { 481 Class<?>[] rawParamTypes = constructor.getParameterTypes(); 482 if (types.length == rawParamTypes.length 483 && rawParamTypes[0] == getDeclaringClass().getEnclosingClass()) { 484 // first parameter is the hidden 'this' 485 return Arrays.copyOfRange(types, 1, types.length); 486 } 487 } 488 return types; 489 } 490 491 @Override 492 @SuppressWarnings({"Java7ApiChecker", "AndroidJdkLibsChecker"}) 493 @IgnoreJRERequirement 494 AnnotatedType[] getAnnotatedParameterTypes() { 495 return constructor.getAnnotatedParameterTypes(); 496 } 497 498 @Override 499 @SuppressWarnings({"Java7ApiChecker", "AndroidJdkLibsChecker", "DoNotCall"}) 500 @DoNotCall 501 @IgnoreJRERequirement 502 public AnnotatedType getAnnotatedReturnType() { 503 return constructor.getAnnotatedReturnType(); 504 } 505 506 @Override 507 Type[] getGenericExceptionTypes() { 508 return constructor.getGenericExceptionTypes(); 509 } 510 511 @Override 512 final Annotation[][] getParameterAnnotations() { 513 return constructor.getParameterAnnotations(); 514 } 515 516 /** 517 * {@inheritDoc} 518 * 519 * <p>{@code [<E>]} will be returned for ArrayList's constructor. When both the class and the 520 * constructor have type parameters, the class parameters are prepended before those of the 521 * constructor's. This is an arbitrary rule since no existing language spec mandates one way or 522 * the other. From the declaration syntax, the class type parameter appears first, but the call 523 * syntax may show up in opposite order such as {@code new <A>Foo<B>()}. 524 */ 525 @Override 526 public final TypeVariable<?>[] getTypeParameters() { 527 TypeVariable<?>[] declaredByClass = getDeclaringClass().getTypeParameters(); 528 TypeVariable<?>[] declaredByConstructor = constructor.getTypeParameters(); 529 TypeVariable<?>[] result = 530 new TypeVariable<?>[declaredByClass.length + declaredByConstructor.length]; 531 System.arraycopy(declaredByClass, 0, result, 0, declaredByClass.length); 532 System.arraycopy( 533 declaredByConstructor, 0, result, declaredByClass.length, declaredByConstructor.length); 534 return result; 535 } 536 537 @Override 538 public final boolean isOverridable() { 539 return false; 540 } 541 542 @Override 543 public final boolean isVarArgs() { 544 return constructor.isVarArgs(); 545 } 546 547 private boolean mayNeedHiddenThis() { 548 Class<?> declaringClass = constructor.getDeclaringClass(); 549 if (declaringClass.getEnclosingConstructor() != null) { 550 // Enclosed in a constructor, needs hidden this 551 return true; 552 } 553 Method enclosingMethod = declaringClass.getEnclosingMethod(); 554 if (enclosingMethod != null) { 555 // Enclosed in a method, if it's not static, must need hidden this. 556 return !Modifier.isStatic(enclosingMethod.getModifiers()); 557 } else { 558 // Strictly, this doesn't necessarily indicate a hidden 'this' in the case of 559 // static initializer. But there seems no way to tell in that case. :( 560 // This may cause issues when an anonymous class is created inside a static initializer, 561 // and the class's constructor's first parameter happens to be the enclosing class. 562 // In such case, we may mistakenly think that the class is within a non-static context 563 // and the first parameter is the hidden 'this'. 564 return declaringClass.getEnclosingClass() != null 565 && !Modifier.isStatic(declaringClass.getModifiers()); 566 } 567 } 568 } 569 570 private static final boolean ANNOTATED_TYPE_EXISTS = initAnnotatedTypeExists(); 571 572 private static boolean initAnnotatedTypeExists() { 573 try { 574 Class.forName("java.lang.reflect.AnnotatedType"); 575 } catch (ClassNotFoundException e) { 576 return false; 577 } 578 return true; 579 } 580}