Coverage Summary for Class: Invokable (com.google.common.reflect)

Class Method, % Line, %
Invokable 42.9% (15/35) 43.5% (27/62)
Invokable$ConstructorInvokable 50% (6/12) 39.5% (15/38)
Invokable$MethodInvokable 63.6% (7/11) 56.2% (9/16)
Total 48.3% (28/58) 44% (51/116)


1 /* 2  * Copyright (C) 2012 The Guava Authors 3  * 4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5  * in compliance with the License. You may obtain a copy of the License at 6  * 7  * http://www.apache.org/licenses/LICENSE-2.0 8  * 9  * Unless required by applicable law or agreed to in writing, software distributed under the License 10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11  * or implied. See the License for the specific language governing permissions and limitations under 12  * the License. 13  */ 14  15 package com.google.common.reflect; 16  17 import static com.google.common.base.Preconditions.checkNotNull; 18  19 import com.google.common.annotations.Beta; 20 import com.google.common.collect.ImmutableList; 21 import com.google.errorprone.annotations.CanIgnoreReturnValue; 22 import java.lang.annotation.Annotation; 23 import java.lang.reflect.AccessibleObject; 24 import java.lang.reflect.AnnotatedElement; 25 import java.lang.reflect.AnnotatedType; 26 import java.lang.reflect.Constructor; 27 import java.lang.reflect.InvocationTargetException; 28 import java.lang.reflect.Member; 29 import java.lang.reflect.Method; 30 import java.lang.reflect.Modifier; 31 import java.lang.reflect.Type; 32 import java.lang.reflect.TypeVariable; 33 import java.util.Arrays; 34 import javax.annotation.CheckForNull; 35 import org.checkerframework.checker.nullness.qual.Nullable; 36  37 /** 38  * Wrapper around either a {@link Method} or a {@link Constructor}. Convenience API is provided to 39  * make common reflective operation easier to deal with, such as {@link #isPublic}, {@link 40  * #getParameters} etc. 41  * 42  * <p>In addition to convenience methods, {@link TypeToken#method} and {@link TypeToken#constructor} 43  * will resolve the type parameters of the method or constructor in the context of the owner type, 44  * which may be a subtype of the declaring class. For example: 45  * 46  * <pre>{@code 47  * Method getMethod = List.class.getMethod("get", int.class); 48  * Invokable<List<String>, ?> invokable = new TypeToken<List<String>>() {}.method(getMethod); 49  * assertEquals(TypeToken.of(String.class), invokable.getReturnType()); // Not Object.class! 50  * assertEquals(new TypeToken<List<String>>() {}, invokable.getOwnerType()); 51  * }</pre> 52  * 53  * <p><b>Note:</b> earlier versions of this class inherited from {@link 54  * java.lang.reflect.AccessibleObject AccessibleObject} and {@link 55  * java.lang.reflect.GenericDeclaration GenericDeclaration}. Since version 31.0 that is no longer 56  * the case. However, most methods from those types are present with the same signature in this 57  * class. 58  * 59  * @param <T> the type that owns this method or constructor. 60  * @param <R> the return type of (or supertype thereof) the method or the declaring type of the 61  * constructor. 62  * @author Ben Yu 63  * @since 14.0 (no longer implements {@link AccessibleObject} or {@code GenericDeclaration} since 64  * 31.0) 65  */ 66 @Beta 67 @ElementTypesAreNonnullByDefault 68 public abstract class Invokable<T, R> implements AnnotatedElement, Member { 69  private final AccessibleObject accessibleObject; 70  private final Member member; 71  72  <M extends AccessibleObject & Member> Invokable(M member) { 73  checkNotNull(member); 74  this.accessibleObject = member; 75  this.member = member; 76  } 77  78  /** Returns {@link Invokable} of {@code method}. */ 79  public static Invokable<?, Object> from(Method method) { 80  return new MethodInvokable<>(method); 81  } 82  83  /** Returns {@link Invokable} of {@code constructor}. */ 84  public static <T> Invokable<T, T> from(Constructor<T> constructor) { 85  return new ConstructorInvokable<T>(constructor); 86  } 87  88  @Override 89  public final boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) { 90  return accessibleObject.isAnnotationPresent(annotationClass); 91  } 92  93  @Override 94  @CheckForNull 95  public final <A extends Annotation> A getAnnotation(Class<A> annotationClass) { 96  return accessibleObject.getAnnotation(annotationClass); 97  } 98  99  @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  public final ImmutableList<Parameter> getParameters() { 277  Type[] parameterTypes = getGenericParameterTypes(); 278  Annotation[][] annotations = getParameterAnnotations(); 279  AnnotatedType[] annotatedTypes = getAnnotatedParameterTypes(); 280  ImmutableList.Builder<Parameter> builder = ImmutableList.builder(); 281  for (int i = 0; i < parameterTypes.length; i++) { 282  builder.add( 283  new Parameter( 284  this, i, TypeToken.of(parameterTypes[i]), annotations[i], annotatedTypes[i])); 285  } 286  return builder.build(); 287  } 288  289  /** Returns all declared exception types of this {@code Invokable}. */ 290  public final ImmutableList<TypeToken<? extends Throwable>> getExceptionTypes() { 291  ImmutableList.Builder<TypeToken<? extends Throwable>> builder = ImmutableList.builder(); 292  for (Type type : getGenericExceptionTypes()) { 293  // getGenericExceptionTypes() will never return a type that's not exception 294  @SuppressWarnings("unchecked") 295  TypeToken<? extends Throwable> exceptionType = 296  (TypeToken<? extends Throwable>) TypeToken.of(type); 297  builder.add(exceptionType); 298  } 299  return builder.build(); 300  } 301  302  /** 303  * Explicitly specifies the return type of this {@code Invokable}. For example: 304  * 305  * <pre>{@code 306  * Method factoryMethod = Person.class.getMethod("create"); 307  * Invokable<?, Person> factory = Invokable.of(getNameMethod).returning(Person.class); 308  * }</pre> 309  */ 310  public final <R1 extends R> Invokable<T, R1> returning(Class<R1> returnType) { 311  return returning(TypeToken.of(returnType)); 312  } 313  314  /** Explicitly specifies the return type of this {@code Invokable}. */ 315  public final <R1 extends R> Invokable<T, R1> returning(TypeToken<R1> returnType) { 316  if (!returnType.isSupertypeOf(getReturnType())) { 317  throw new IllegalArgumentException( 318  "Invokable is known to return " + getReturnType() + ", not " + returnType); 319  } 320  @SuppressWarnings("unchecked") // guarded by previous check 321  Invokable<T, R1> specialized = (Invokable<T, R1>) this; 322  return specialized; 323  } 324  325  @SuppressWarnings("unchecked") // The declaring class is T's raw class, or one of its supertypes. 326  @Override 327  public final Class<? super T> getDeclaringClass() { 328  return (Class<? super T>) member.getDeclaringClass(); 329  } 330  331  /** Returns the type of {@code T}. */ 332  // Overridden in TypeToken#method() and TypeToken#constructor() 333  @SuppressWarnings("unchecked") // The declaring class is T. 334  public TypeToken<T> getOwnerType() { 335  return (TypeToken<T>) TypeToken.of(getDeclaringClass()); 336  } 337  338  @CheckForNull 339  abstract Object invokeInternal(@CheckForNull Object receiver, @Nullable Object[] args) 340  throws InvocationTargetException, IllegalAccessException; 341  342  abstract Type[] getGenericParameterTypes(); 343  344  abstract AnnotatedType[] getAnnotatedParameterTypes(); 345  346  /** This should never return a type that's not a subtype of Throwable. */ 347  abstract Type[] getGenericExceptionTypes(); 348  349  abstract Annotation[][] getParameterAnnotations(); 350  351  abstract Type getGenericReturnType(); 352  353  public abstract AnnotatedType getAnnotatedReturnType(); 354  355  static class MethodInvokable<T> extends Invokable<T, Object> { 356  357  final Method method; 358  359  MethodInvokable(Method method) { 360  super(method); 361  this.method = method; 362  } 363  364  @Override 365  @CheckForNull 366  final Object invokeInternal(@CheckForNull Object receiver, @Nullable Object[] args) 367  throws InvocationTargetException, IllegalAccessException { 368  return method.invoke(receiver, args); 369  } 370  371  @Override 372  Type getGenericReturnType() { 373  return method.getGenericReturnType(); 374  } 375  376  @Override 377  Type[] getGenericParameterTypes() { 378  return method.getGenericParameterTypes(); 379  } 380  381  @Override 382  AnnotatedType[] getAnnotatedParameterTypes() { 383  return method.getAnnotatedParameterTypes(); 384  } 385  386  @Override 387  public AnnotatedType getAnnotatedReturnType() { 388  return method.getAnnotatedReturnType(); 389  } 390  391  @Override 392  Type[] getGenericExceptionTypes() { 393  return method.getGenericExceptionTypes(); 394  } 395  396  @Override 397  final Annotation[][] getParameterAnnotations() { 398  return method.getParameterAnnotations(); 399  } 400  401  @Override 402  public final TypeVariable<?>[] getTypeParameters() { 403  return method.getTypeParameters(); 404  } 405  406  @Override 407  public final boolean isOverridable() { 408  return !(isFinal() 409  || isPrivate() 410  || isStatic() 411  || Modifier.isFinal(getDeclaringClass().getModifiers())); 412  } 413  414  @Override 415  public final boolean isVarArgs() { 416  return method.isVarArgs(); 417  } 418  } 419  420  static class ConstructorInvokable<T> extends Invokable<T, T> { 421  422  final Constructor<?> constructor; 423  424  ConstructorInvokable(Constructor<?> constructor) { 425  super(constructor); 426  this.constructor = constructor; 427  } 428  429  @Override 430  final Object invokeInternal(@CheckForNull Object receiver, @Nullable Object[] args) 431  throws InvocationTargetException, IllegalAccessException { 432  try { 433  return constructor.newInstance(args); 434  } catch (InstantiationException e) { 435  throw new RuntimeException(constructor + " failed.", e); 436  } 437  } 438  439  /** 440  * If the class is parameterized, such as {@link java.util.ArrayList ArrayList}, this returns 441  * {@code ArrayList<E>}. 442  */ 443  @Override 444  Type getGenericReturnType() { 445  Class<?> declaringClass = getDeclaringClass(); 446  TypeVariable<?>[] typeParams = declaringClass.getTypeParameters(); 447  if (typeParams.length > 0) { 448  return Types.newParameterizedType(declaringClass, typeParams); 449  } else { 450  return declaringClass; 451  } 452  } 453  454  @Override 455  Type[] getGenericParameterTypes() { 456  Type[] types = constructor.getGenericParameterTypes(); 457  if (types.length > 0 && mayNeedHiddenThis()) { 458  Class<?>[] rawParamTypes = constructor.getParameterTypes(); 459  if (types.length == rawParamTypes.length 460  && rawParamTypes[0] == getDeclaringClass().getEnclosingClass()) { 461  // first parameter is the hidden 'this' 462  return Arrays.copyOfRange(types, 1, types.length); 463  } 464  } 465  return types; 466  } 467  468  @Override 469  AnnotatedType[] getAnnotatedParameterTypes() { 470  return constructor.getAnnotatedParameterTypes(); 471  } 472  473  @Override 474  public AnnotatedType getAnnotatedReturnType() { 475  return constructor.getAnnotatedReturnType(); 476  } 477  478  @Override 479  Type[] getGenericExceptionTypes() { 480  return constructor.getGenericExceptionTypes(); 481  } 482  483  @Override 484  final Annotation[][] getParameterAnnotations() { 485  return constructor.getParameterAnnotations(); 486  } 487  488  /** 489  * {@inheritDoc} 490  * 491  * <p>{@code [<E>]} will be returned for ArrayList's constructor. When both the class and the 492  * constructor have type parameters, the class parameters are prepended before those of the 493  * constructor's. This is an arbitrary rule since no existing language spec mandates one way or 494  * the other. From the declaration syntax, the class type parameter appears first, but the call 495  * syntax may show up in opposite order such as {@code new <A>Foo<B>()}. 496  */ 497  @Override 498  public final TypeVariable<?>[] getTypeParameters() { 499  TypeVariable<?>[] declaredByClass = getDeclaringClass().getTypeParameters(); 500  TypeVariable<?>[] declaredByConstructor = constructor.getTypeParameters(); 501  TypeVariable<?>[] result = 502  new TypeVariable<?>[declaredByClass.length + declaredByConstructor.length]; 503  System.arraycopy(declaredByClass, 0, result, 0, declaredByClass.length); 504  System.arraycopy( 505  declaredByConstructor, 0, result, declaredByClass.length, declaredByConstructor.length); 506  return result; 507  } 508  509  @Override 510  public final boolean isOverridable() { 511  return false; 512  } 513  514  @Override 515  public final boolean isVarArgs() { 516  return constructor.isVarArgs(); 517  } 518  519  private boolean mayNeedHiddenThis() { 520  Class<?> declaringClass = constructor.getDeclaringClass(); 521  if (declaringClass.getEnclosingConstructor() != null) { 522  // Enclosed in a constructor, needs hidden this 523  return true; 524  } 525  Method enclosingMethod = declaringClass.getEnclosingMethod(); 526  if (enclosingMethod != null) { 527  // Enclosed in a method, if it's not static, must need hidden this. 528  return !Modifier.isStatic(enclosingMethod.getModifiers()); 529  } else { 530  // Strictly, this doesn't necessarily indicate a hidden 'this' in the case of 531  // static initializer. But there seems no way to tell in that case. :( 532  // This may cause issues when an anonymous class is created inside a static initializer, 533  // and the class's constructor's first parameter happens to be the enclosing class. 534  // In such case, we may mistakenly think that the class is within a non-static context 535  // and the first parameter is the hidden 'this'. 536  return declaringClass.getEnclosingClass() != null 537  && !Modifier.isStatic(declaringClass.getModifiers()); 538  } 539  } 540  } 541 }