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 java.lang.annotation.Annotation;
023import java.lang.reflect.AccessibleObject;
024import java.lang.reflect.AnnotatedType;
025import java.lang.reflect.Constructor;
026import java.lang.reflect.GenericDeclaration;
027import java.lang.reflect.InvocationTargetException;
028import java.lang.reflect.Member;
029import java.lang.reflect.Method;
030import java.lang.reflect.Modifier;
031import java.lang.reflect.Type;
032import java.lang.reflect.TypeVariable;
033import java.util.Arrays;
034import org.checkerframework.checker.nullness.qual.Nullable;
035
036/**
037 * Wrapper around either a {@link Method} or a {@link Constructor}. Convenience API is provided to
038 * make common reflective operation easier to deal with, such as {@link #isPublic}, {@link
039 * #getParameters} etc.
040 *
041 * <p>In addition to convenience methods, {@link TypeToken#method} and {@link TypeToken#constructor}
042 * will resolve the type parameters of the method or constructor in the context of the owner type,
043 * which may be a subtype of the declaring class. For example:
044 *
045 * <pre>{@code
046 * Method getMethod = List.class.getMethod("get", int.class);
047 * Invokable<List<String>, ?> invokable = new TypeToken<List<String>>() {}.method(getMethod);
048 * assertEquals(TypeToken.of(String.class), invokable.getReturnType()); // Not Object.class!
049 * assertEquals(new TypeToken<List<String>>() {}, invokable.getOwnerType());
050 * }</pre>
051 *
052 * @param <T> the type that owns this method or constructor.
053 * @param <R> the return type of (or supertype thereof) the method or the declaring type of the
054 *     constructor.
055 * @author Ben Yu
056 * @since 14.0
057 */
058@Beta
059public abstract class Invokable<T, R> extends Element implements GenericDeclaration {
060
061  <M extends AccessibleObject & Member> Invokable(M member) {
062    super(member);
063  }
064
065  /** Returns {@link Invokable} of {@code method}. */
066  public static Invokable<?, Object> from(Method method) {
067    return new MethodInvokable<>(method);
068  }
069
070  /** Returns {@link Invokable} of {@code constructor}. */
071  public static <T> Invokable<T, T> from(Constructor<T> constructor) {
072    return new ConstructorInvokable<T>(constructor);
073  }
074
075  /**
076   * Returns {@code true} if this is an overridable method. Constructors, private, static or final
077   * methods, or methods declared by final classes are not overridable.
078   */
079  public abstract boolean isOverridable();
080
081  /** Returns {@code true} if this was declared to take a variable number of arguments. */
082  public abstract boolean isVarArgs();
083
084  /**
085   * Invokes with {@code receiver} as 'this' and {@code args} passed to the underlying method and
086   * returns the return value; or calls the underlying constructor with {@code args} and returns the
087   * constructed instance.
088   *
089   * @throws IllegalAccessException if this {@code Constructor} object enforces Java language access
090   *     control and the underlying method or constructor is inaccessible.
091   * @throws IllegalArgumentException if the number of actual and formal parameters differ; if an
092   *     unwrapping conversion for primitive arguments fails; or if, after possible unwrapping, a
093   *     parameter value cannot be converted to the corresponding formal parameter type by a method
094   *     invocation conversion.
095   * @throws InvocationTargetException if the underlying method or constructor throws an exception.
096   */
097  // All subclasses are owned by us and we'll make sure to get the R type right.
098  @SuppressWarnings("unchecked")
099  @CanIgnoreReturnValue
100  public final R invoke(@Nullable T receiver, Object... args)
101      throws InvocationTargetException, IllegalAccessException {
102    return (R) invokeInternal(receiver, checkNotNull(args));
103  }
104
105  /** Returns the return type of this {@code Invokable}. */
106  // All subclasses are owned by us and we'll make sure to get the R type right.
107  @SuppressWarnings("unchecked")
108  public final TypeToken<? extends R> getReturnType() {
109    return (TypeToken<? extends R>) TypeToken.of(getGenericReturnType());
110  }
111
112  /**
113   * Returns all declared parameters of this {@code Invokable}. Note that if this is a constructor
114   * of a non-static inner class, unlike {@link Constructor#getParameterTypes}, the hidden {@code
115   * this} parameter of the enclosing class is excluded from the returned parameters.
116   */
117  public final ImmutableList<Parameter> getParameters() {
118    Type[] parameterTypes = getGenericParameterTypes();
119    Annotation[][] annotations = getParameterAnnotations();
120    AnnotatedType[] annotatedTypes = getAnnotatedParameterTypes();
121    ImmutableList.Builder<Parameter> builder = ImmutableList.builder();
122    for (int i = 0; i < parameterTypes.length; i++) {
123      builder.add(
124          new Parameter(
125              this, i, TypeToken.of(parameterTypes[i]), annotations[i], annotatedTypes[i]));
126    }
127    return builder.build();
128  }
129
130  /** Returns all declared exception types of this {@code Invokable}. */
131  public final ImmutableList<TypeToken<? extends Throwable>> getExceptionTypes() {
132    ImmutableList.Builder<TypeToken<? extends Throwable>> builder = ImmutableList.builder();
133    for (Type type : getGenericExceptionTypes()) {
134      // getGenericExceptionTypes() will never return a type that's not exception
135      @SuppressWarnings("unchecked")
136      TypeToken<? extends Throwable> exceptionType =
137          (TypeToken<? extends Throwable>) TypeToken.of(type);
138      builder.add(exceptionType);
139    }
140    return builder.build();
141  }
142
143  /**
144   * Explicitly specifies the return type of this {@code Invokable}. For example:
145   *
146   * <pre>{@code
147   * Method factoryMethod = Person.class.getMethod("create");
148   * Invokable<?, Person> factory = Invokable.of(getNameMethod).returning(Person.class);
149   * }</pre>
150   */
151  public final <R1 extends R> Invokable<T, R1> returning(Class<R1> returnType) {
152    return returning(TypeToken.of(returnType));
153  }
154
155  /** Explicitly specifies the return type of this {@code Invokable}. */
156  public final <R1 extends R> Invokable<T, R1> returning(TypeToken<R1> returnType) {
157    if (!returnType.isSupertypeOf(getReturnType())) {
158      throw new IllegalArgumentException(
159          "Invokable is known to return " + getReturnType() + ", not " + returnType);
160    }
161    @SuppressWarnings("unchecked") // guarded by previous check
162    Invokable<T, R1> specialized = (Invokable<T, R1>) this;
163    return specialized;
164  }
165
166  @SuppressWarnings("unchecked") // The declaring class is T's raw class, or one of its supertypes.
167  @Override
168  public final Class<? super T> getDeclaringClass() {
169    return (Class<? super T>) super.getDeclaringClass();
170  }
171
172  /** Returns the type of {@code T}. */
173  // Overridden in TypeToken#method() and TypeToken#constructor()
174  @SuppressWarnings("unchecked") // The declaring class is T.
175  @Override
176  public TypeToken<T> getOwnerType() {
177    return (TypeToken<T>) TypeToken.of(getDeclaringClass());
178  }
179
180  abstract Object invokeInternal(@Nullable Object receiver, Object[] args)
181      throws InvocationTargetException, IllegalAccessException;
182
183  abstract Type[] getGenericParameterTypes();
184
185  abstract AnnotatedType[] getAnnotatedParameterTypes();
186
187  /** This should never return a type that's not a subtype of Throwable. */
188  abstract Type[] getGenericExceptionTypes();
189
190  abstract Annotation[][] getParameterAnnotations();
191
192  abstract Type getGenericReturnType();
193
194  public abstract AnnotatedType getAnnotatedReturnType();
195
196  static class MethodInvokable<T> extends Invokable<T, Object> {
197
198    final Method method;
199
200    MethodInvokable(Method method) {
201      super(method);
202      this.method = method;
203    }
204
205    @Override
206    final Object invokeInternal(@Nullable Object receiver, Object[] args)
207        throws InvocationTargetException, IllegalAccessException {
208      return method.invoke(receiver, args);
209    }
210
211    @Override
212    Type getGenericReturnType() {
213      return method.getGenericReturnType();
214    }
215
216    @Override
217    Type[] getGenericParameterTypes() {
218      return method.getGenericParameterTypes();
219    }
220
221    @Override
222    AnnotatedType[] getAnnotatedParameterTypes() {
223      return method.getAnnotatedParameterTypes();
224    }
225
226    @Override
227    public AnnotatedType getAnnotatedReturnType() {
228      return method.getAnnotatedReturnType();
229    }
230
231    @Override
232    Type[] getGenericExceptionTypes() {
233      return method.getGenericExceptionTypes();
234    }
235
236    @Override
237    final Annotation[][] getParameterAnnotations() {
238      return method.getParameterAnnotations();
239    }
240
241    @Override
242    public final TypeVariable<?>[] getTypeParameters() {
243      return method.getTypeParameters();
244    }
245
246    @Override
247    public final boolean isOverridable() {
248      return !(isFinal()
249          || isPrivate()
250          || isStatic()
251          || Modifier.isFinal(getDeclaringClass().getModifiers()));
252    }
253
254    @Override
255    public final boolean isVarArgs() {
256      return method.isVarArgs();
257    }
258  }
259
260  static class ConstructorInvokable<T> extends Invokable<T, T> {
261
262    final Constructor<?> constructor;
263
264    ConstructorInvokable(Constructor<?> constructor) {
265      super(constructor);
266      this.constructor = constructor;
267    }
268
269    @Override
270    final Object invokeInternal(@Nullable Object receiver, Object[] args)
271        throws InvocationTargetException, IllegalAccessException {
272      try {
273        return constructor.newInstance(args);
274      } catch (InstantiationException e) {
275        throw new RuntimeException(constructor + " failed.", e);
276      }
277    }
278
279    /**
280     * If the class is parameterized, such as {@link java.util.ArrayList ArrayList}, this returns
281     * {@code ArrayList<E>}.
282     */
283    @Override
284    Type getGenericReturnType() {
285      Class<?> declaringClass = getDeclaringClass();
286      TypeVariable<?>[] typeParams = declaringClass.getTypeParameters();
287      if (typeParams.length > 0) {
288        return Types.newParameterizedType(declaringClass, typeParams);
289      } else {
290        return declaringClass;
291      }
292    }
293
294    @Override
295    Type[] getGenericParameterTypes() {
296      Type[] types = constructor.getGenericParameterTypes();
297      if (types.length > 0 && mayNeedHiddenThis()) {
298        Class<?>[] rawParamTypes = constructor.getParameterTypes();
299        if (types.length == rawParamTypes.length
300            && rawParamTypes[0] == getDeclaringClass().getEnclosingClass()) {
301          // first parameter is the hidden 'this'
302          return Arrays.copyOfRange(types, 1, types.length);
303        }
304      }
305      return types;
306    }
307
308    @Override
309    AnnotatedType[] getAnnotatedParameterTypes() {
310      return constructor.getAnnotatedParameterTypes();
311    }
312
313    @Override
314    public AnnotatedType getAnnotatedReturnType() {
315      return constructor.getAnnotatedReturnType();
316    }
317
318    @Override
319    Type[] getGenericExceptionTypes() {
320      return constructor.getGenericExceptionTypes();
321    }
322
323    @Override
324    final Annotation[][] getParameterAnnotations() {
325      return constructor.getParameterAnnotations();
326    }
327
328    /**
329     * {@inheritDoc}
330     *
331     * <p>{@code [<E>]} will be returned for ArrayList's constructor. When both the class and the
332     * constructor have type parameters, the class parameters are prepended before those of the
333     * constructor's. This is an arbitrary rule since no existing language spec mandates one way or
334     * the other. From the declaration syntax, the class type parameter appears first, but the call
335     * syntax may show up in opposite order such as {@code new <A>Foo<B>()}.
336     */
337    @Override
338    public final TypeVariable<?>[] getTypeParameters() {
339      TypeVariable<?>[] declaredByClass = getDeclaringClass().getTypeParameters();
340      TypeVariable<?>[] declaredByConstructor = constructor.getTypeParameters();
341      TypeVariable<?>[] result =
342          new TypeVariable<?>[declaredByClass.length + declaredByConstructor.length];
343      System.arraycopy(declaredByClass, 0, result, 0, declaredByClass.length);
344      System.arraycopy(
345          declaredByConstructor, 0, result, declaredByClass.length, declaredByConstructor.length);
346      return result;
347    }
348
349    @Override
350    public final boolean isOverridable() {
351      return false;
352    }
353
354    @Override
355    public final boolean isVarArgs() {
356      return constructor.isVarArgs();
357    }
358
359    private boolean mayNeedHiddenThis() {
360      Class<?> declaringClass = constructor.getDeclaringClass();
361      if (declaringClass.getEnclosingConstructor() != null) {
362        // Enclosed in a constructor, needs hidden this
363        return true;
364      }
365      Method enclosingMethod = declaringClass.getEnclosingMethod();
366      if (enclosingMethod != null) {
367        // Enclosed in a method, if it's not static, must need hidden this.
368        return !Modifier.isStatic(enclosingMethod.getModifiers());
369      } else {
370        // Strictly, this doesn't necessarily indicate a hidden 'this' in the case of
371        // static initializer. But there seems no way to tell in that case. :(
372        // This may cause issues when an anonymous class is created inside a static initializer,
373        // and the class's constructor's first parameter happens to be the enclosing class.
374        // In such case, we may mistakenly think that the class is within a non-static context
375        // and the first parameter is the hidden 'this'.
376        return declaringClass.getEnclosingClass() != null
377            && !Modifier.isStatic(declaringClass.getModifiers());
378      }
379    }
380  }
381}