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.collect.ImmutableList;
020import com.google.errorprone.annotations.CanIgnoreReturnValue;
021import java.lang.annotation.Annotation;
022import java.lang.reflect.AccessibleObject;
023import java.lang.reflect.AnnotatedElement;
024import java.lang.reflect.Constructor;
025import java.lang.reflect.InvocationTargetException;
026import java.lang.reflect.Member;
027import java.lang.reflect.Method;
028import java.lang.reflect.Modifier;
029import java.lang.reflect.Type;
030import java.lang.reflect.TypeVariable;
031import java.util.Arrays;
032import javax.annotation.CheckForNull;
033import org.checkerframework.checker.nullness.qual.Nullable;
034
035/**
036 * Wrapper around either a {@link Method} or a {@link Constructor}. Convenience API is provided to
037 * make common reflective operation easier to deal with, such as {@link #isPublic}, {@link
038 * #getParameters} etc.
039 *
040 * <p>In addition to convenience methods, {@link TypeToken#method} and {@link TypeToken#constructor}
041 * will resolve the type parameters of the method or constructor in the context of the owner type,
042 * which may be a subtype of the declaring class. For example:
043 *
044 * <pre>{@code
045 * Method getMethod = List.class.getMethod("get", int.class);
046 * Invokable<List<String>, ?> invokable = new TypeToken<List<String>>() {}.method(getMethod);
047 * assertEquals(TypeToken.of(String.class), invokable.getReturnType()); // Not Object.class!
048 * assertEquals(new TypeToken<List<String>>() {}, invokable.getOwnerType());
049 * }</pre>
050 *
051 * <p><b>Note:</b> earlier versions of this class inherited from {@link
052 * java.lang.reflect.AccessibleObject AccessibleObject} and {@link
053 * java.lang.reflect.GenericDeclaration GenericDeclaration}. Since version 31.0 that is no longer
054 * the case. However, most methods from those types are present with the same signature in this
055 * class.
056 *
057 * @param <T> the type that owns this method or constructor.
058 * @param <R> the return type of (or supertype thereof) the method or the declaring type of the
059 *     constructor.
060 * @author Ben Yu
061 * @since 14.0 (no longer implements {@link AccessibleObject} or {@code GenericDeclaration} since
062 *     31.0)
063 */
064@ElementTypesAreNonnullByDefault
065public abstract class Invokable<T, R> implements AnnotatedElement, Member {
066  private final AccessibleObject accessibleObject;
067  private final Member member;
068
069  <M extends AccessibleObject & Member> Invokable(M member) {
070    checkNotNull(member);
071    this.accessibleObject = member;
072    this.member = member;
073  }
074
075  /** Returns {@link Invokable} of {@code method}. */
076  public static Invokable<?, Object> from(Method method) {
077    return new MethodInvokable<>(method);
078  }
079
080  /** Returns {@link Invokable} of {@code constructor}. */
081  public static <T> Invokable<T, T> from(Constructor<T> constructor) {
082    return new ConstructorInvokable<T>(constructor);
083  }
084
085  @Override
086  public final boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
087    return accessibleObject.isAnnotationPresent(annotationClass);
088  }
089
090  @Override
091  @CheckForNull
092  public final <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
093    return accessibleObject.getAnnotation(annotationClass);
094  }
095
096  @Override
097  public final Annotation[] getAnnotations() {
098    return accessibleObject.getAnnotations();
099  }
100
101  @Override
102  public final Annotation[] getDeclaredAnnotations() {
103    return accessibleObject.getDeclaredAnnotations();
104  }
105
106  // We ought to be able to implement GenericDeclaration instead its parent AnnotatedElement.
107  // That would give us this method declaration. But for some reason, implementing
108  // GenericDeclaration leads to weird errors in Android tests:
109  // IncompatibleClassChangeError: interface not implemented
110  /** See {@link java.lang.reflect.GenericDeclaration#getTypeParameters()}. */
111  public abstract TypeVariable<?>[] getTypeParameters();
112
113  /** See {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)}. */
114  public final void setAccessible(boolean flag) {
115    accessibleObject.setAccessible(flag);
116  }
117
118  /** See {@link java.lang.reflect.AccessibleObject#trySetAccessible()}. */
119  @SuppressWarnings("CatchingUnchecked") // sneaky checked exception
120  public final boolean trySetAccessible() {
121    // We can't call accessibleObject.trySetAccessible since that was added in Java 9 and this code
122    // should work on Java 8. So we emulate it this way.
123    try {
124      accessibleObject.setAccessible(true);
125      return true;
126    } catch (Exception e) { // sneaky checked exception
127      return false;
128    }
129  }
130
131  /** See {@link java.lang.reflect.AccessibleObject#isAccessible()}. */
132  public final boolean isAccessible() {
133    return accessibleObject.isAccessible();
134  }
135
136  @Override
137  public final String getName() {
138    return member.getName();
139  }
140
141  @Override
142  public final int getModifiers() {
143    return member.getModifiers();
144  }
145
146  @Override
147  public final boolean isSynthetic() {
148    return member.isSynthetic();
149  }
150
151  /** Returns true if the element is public. */
152  public final boolean isPublic() {
153    return Modifier.isPublic(getModifiers());
154  }
155
156  /** Returns true if the element is protected. */
157  public final boolean isProtected() {
158    return Modifier.isProtected(getModifiers());
159  }
160
161  /** Returns true if the element is package-private. */
162  public final boolean isPackagePrivate() {
163    return !isPrivate() && !isPublic() && !isProtected();
164  }
165
166  /** Returns true if the element is private. */
167  public final boolean isPrivate() {
168    return Modifier.isPrivate(getModifiers());
169  }
170
171  /** Returns true if the element is static. */
172  public final boolean isStatic() {
173    return Modifier.isStatic(getModifiers());
174  }
175
176  /**
177   * Returns {@code true} if this method is final, per {@code Modifier.isFinal(getModifiers())}.
178   *
179   * <p>Note that a method may still be effectively "final", or non-overridable when it has no
180   * {@code final} keyword. For example, it could be private, or it could be declared by a final
181   * class. To tell whether a method is overridable, use {@link Invokable#isOverridable}.
182   */
183  public final boolean isFinal() {
184    return Modifier.isFinal(getModifiers());
185  }
186
187  /** Returns true if the method is abstract. */
188  public final boolean isAbstract() {
189    return Modifier.isAbstract(getModifiers());
190  }
191
192  /** Returns true if the element is native. */
193  public final boolean isNative() {
194    return Modifier.isNative(getModifiers());
195  }
196
197  /** Returns true if the method is synchronized. */
198  public final boolean isSynchronized() {
199    return Modifier.isSynchronized(getModifiers());
200  }
201
202  /** Returns true if the field is volatile. */
203  final boolean isVolatile() {
204    return Modifier.isVolatile(getModifiers());
205  }
206
207  /** Returns true if the field is transient. */
208  final boolean isTransient() {
209    return Modifier.isTransient(getModifiers());
210  }
211
212  @Override
213  public boolean equals(@CheckForNull Object obj) {
214    if (obj instanceof Invokable) {
215      Invokable<?, ?> that = (Invokable<?, ?>) obj;
216      return getOwnerType().equals(that.getOwnerType()) && member.equals(that.member);
217    }
218    return false;
219  }
220
221  @Override
222  public int hashCode() {
223    return member.hashCode();
224  }
225
226  @Override
227  public String toString() {
228    return member.toString();
229  }
230
231  /**
232   * Returns {@code true} if this is an overridable method. Constructors, private, static or final
233   * methods, or methods declared by final classes are not overridable.
234   */
235  public abstract boolean isOverridable();
236
237  /** Returns {@code true} if this was declared to take a variable number of arguments. */
238  public abstract boolean isVarArgs();
239
240  /**
241   * Invokes with {@code receiver} as 'this' and {@code args} passed to the underlying method and
242   * returns the return value; or calls the underlying constructor with {@code args} and returns the
243   * constructed instance.
244   *
245   * @throws IllegalAccessException if this {@code Constructor} object enforces Java language access
246   *     control and the underlying method or constructor is inaccessible.
247   * @throws IllegalArgumentException if the number of actual and formal parameters differ; if an
248   *     unwrapping conversion for primitive arguments fails; or if, after possible unwrapping, a
249   *     parameter value cannot be converted to the corresponding formal parameter type by a method
250   *     invocation conversion.
251   * @throws InvocationTargetException if the underlying method or constructor throws an exception.
252   */
253  // All subclasses are owned by us and we'll make sure to get the R type right, including nullness.
254  @SuppressWarnings({"unchecked", "nullness"})
255  @CanIgnoreReturnValue
256  @CheckForNull
257  public final R invoke(@CheckForNull T receiver, @Nullable Object... args)
258      throws InvocationTargetException, IllegalAccessException {
259    return (R) invokeInternal(receiver, checkNotNull(args));
260  }
261
262  /** Returns the return type of this {@code Invokable}. */
263  // All subclasses are owned by us and we'll make sure to get the R type right.
264  @SuppressWarnings("unchecked")
265  public final TypeToken<? extends R> getReturnType() {
266    return (TypeToken<? extends R>) TypeToken.of(getGenericReturnType());
267  }
268
269  /**
270   * Returns all declared parameters of this {@code Invokable}. Note that if this is a constructor
271   * of a non-static inner class, unlike {@link Constructor#getParameterTypes}, the hidden {@code
272   * this} parameter of the enclosing class is excluded from the returned parameters.
273   */
274  @IgnoreJRERequirement
275  public final ImmutableList<Parameter> getParameters() {
276    Type[] parameterTypes = getGenericParameterTypes();
277    Annotation[][] annotations = getParameterAnnotations();
278    @Nullable Object[] annotatedTypes =
279        new Object[parameterTypes.length];
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  /** This should never return a type that's not a subtype of Throwable. */
345  abstract Type[] getGenericExceptionTypes();
346
347  abstract Annotation[][] getParameterAnnotations();
348
349  abstract Type getGenericReturnType();
350
351  static class MethodInvokable<T> extends Invokable<T, Object> {
352
353    final Method method;
354
355    MethodInvokable(Method method) {
356      super(method);
357      this.method = method;
358    }
359
360    @Override
361    @CheckForNull
362    final Object invokeInternal(@CheckForNull Object receiver, @Nullable Object[] args)
363        throws InvocationTargetException, IllegalAccessException {
364      return method.invoke(receiver, args);
365    }
366
367    @Override
368    Type getGenericReturnType() {
369      return method.getGenericReturnType();
370    }
371
372    @Override
373    Type[] getGenericParameterTypes() {
374      return method.getGenericParameterTypes();
375    }
376
377    @Override
378    Type[] getGenericExceptionTypes() {
379      return method.getGenericExceptionTypes();
380    }
381
382    @Override
383    final Annotation[][] getParameterAnnotations() {
384      return method.getParameterAnnotations();
385    }
386
387    @Override
388    public final TypeVariable<?>[] getTypeParameters() {
389      return method.getTypeParameters();
390    }
391
392    @Override
393    public final boolean isOverridable() {
394      return !(isFinal()
395          || isPrivate()
396          || isStatic()
397          || Modifier.isFinal(getDeclaringClass().getModifiers()));
398    }
399
400    @Override
401    public final boolean isVarArgs() {
402      return method.isVarArgs();
403    }
404  }
405
406  static class ConstructorInvokable<T> extends Invokable<T, T> {
407
408    final Constructor<?> constructor;
409
410    ConstructorInvokable(Constructor<?> constructor) {
411      super(constructor);
412      this.constructor = constructor;
413    }
414
415    @Override
416    final Object invokeInternal(@CheckForNull Object receiver, @Nullable Object[] args)
417        throws InvocationTargetException, IllegalAccessException {
418      try {
419        return constructor.newInstance(args);
420      } catch (InstantiationException e) {
421        throw new RuntimeException(constructor + " failed.", e);
422      }
423    }
424
425    /**
426     * If the class is parameterized, such as {@link java.util.ArrayList ArrayList}, this returns
427     * {@code ArrayList<E>}.
428     */
429    @Override
430    Type getGenericReturnType() {
431      Class<?> declaringClass = getDeclaringClass();
432      TypeVariable<?>[] typeParams = declaringClass.getTypeParameters();
433      if (typeParams.length > 0) {
434        return Types.newParameterizedType(declaringClass, typeParams);
435      } else {
436        return declaringClass;
437      }
438    }
439
440    @Override
441    Type[] getGenericParameterTypes() {
442      Type[] types = constructor.getGenericParameterTypes();
443      if (types.length > 0 && mayNeedHiddenThis()) {
444        Class<?>[] rawParamTypes = constructor.getParameterTypes();
445        if (types.length == rawParamTypes.length
446            && rawParamTypes[0] == getDeclaringClass().getEnclosingClass()) {
447          // first parameter is the hidden 'this'
448          return Arrays.copyOfRange(types, 1, types.length);
449        }
450      }
451      return types;
452    }
453
454    @Override
455    Type[] getGenericExceptionTypes() {
456      return constructor.getGenericExceptionTypes();
457    }
458
459    @Override
460    final Annotation[][] getParameterAnnotations() {
461      return constructor.getParameterAnnotations();
462    }
463
464    /**
465     * {@inheritDoc}
466     *
467     * <p>{@code [<E>]} will be returned for ArrayList's constructor. When both the class and the
468     * constructor have type parameters, the class parameters are prepended before those of the
469     * constructor's. This is an arbitrary rule since no existing language spec mandates one way or
470     * the other. From the declaration syntax, the class type parameter appears first, but the call
471     * syntax may show up in opposite order such as {@code new <A>Foo<B>()}.
472     */
473    @Override
474    public final TypeVariable<?>[] getTypeParameters() {
475      TypeVariable<?>[] declaredByClass = getDeclaringClass().getTypeParameters();
476      TypeVariable<?>[] declaredByConstructor = constructor.getTypeParameters();
477      TypeVariable<?>[] result =
478          new TypeVariable<?>[declaredByClass.length + declaredByConstructor.length];
479      System.arraycopy(declaredByClass, 0, result, 0, declaredByClass.length);
480      System.arraycopy(
481          declaredByConstructor, 0, result, declaredByClass.length, declaredByConstructor.length);
482      return result;
483    }
484
485    @Override
486    public final boolean isOverridable() {
487      return false;
488    }
489
490    @Override
491    public final boolean isVarArgs() {
492      return constructor.isVarArgs();
493    }
494
495    private boolean mayNeedHiddenThis() {
496      Class<?> declaringClass = constructor.getDeclaringClass();
497      if (declaringClass.getEnclosingConstructor() != null) {
498        // Enclosed in a constructor, needs hidden this
499        return true;
500      }
501      Method enclosingMethod = declaringClass.getEnclosingMethod();
502      if (enclosingMethod != null) {
503        // Enclosed in a method, if it's not static, must need hidden this.
504        return !Modifier.isStatic(enclosingMethod.getModifiers());
505      } else {
506        // Strictly, this doesn't necessarily indicate a hidden 'this' in the case of
507        // static initializer. But there seems no way to tell in that case. :(
508        // This may cause issues when an anonymous class is created inside a static initializer,
509        // and the class's constructor's first parameter happens to be the enclosing class.
510        // In such case, we may mistakenly think that the class is within a non-static context
511        // and the first parameter is the hidden 'this'.
512        return declaringClass.getEnclosingClass() != null
513            && !Modifier.isStatic(declaringClass.getModifiers());
514      }
515    }
516  }
517
518  private static final boolean ANNOTATED_TYPE_EXISTS = initAnnotatedTypeExists();
519
520  private static boolean initAnnotatedTypeExists() {
521    try {
522      Class.forName("java.lang.reflect.AnnotatedType");
523    } catch (ClassNotFoundException e) {
524      return false;
525    }
526    return true;
527  }
528}