17dd252788645e940eada959bdde927426e2531c9Paul Duffin/*
27dd252788645e940eada959bdde927426e2531c9Paul Duffin * Copyright (C) 2012 The Guava Authors
37dd252788645e940eada959bdde927426e2531c9Paul Duffin *
47dd252788645e940eada959bdde927426e2531c9Paul Duffin * Licensed under the Apache License, Version 2.0 (the "License");
57dd252788645e940eada959bdde927426e2531c9Paul Duffin * you may not use this file except in compliance with the License.
67dd252788645e940eada959bdde927426e2531c9Paul Duffin * You may obtain a copy of the License at
77dd252788645e940eada959bdde927426e2531c9Paul Duffin *
87dd252788645e940eada959bdde927426e2531c9Paul Duffin * http://www.apache.org/licenses/LICENSE-2.0
97dd252788645e940eada959bdde927426e2531c9Paul Duffin *
107dd252788645e940eada959bdde927426e2531c9Paul Duffin * Unless required by applicable law or agreed to in writing, software
117dd252788645e940eada959bdde927426e2531c9Paul Duffin * distributed under the License is distributed on an "AS IS" BASIS,
127dd252788645e940eada959bdde927426e2531c9Paul Duffin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137dd252788645e940eada959bdde927426e2531c9Paul Duffin * See the License for the specific language governing permissions and
147dd252788645e940eada959bdde927426e2531c9Paul Duffin * limitations under the License.
157dd252788645e940eada959bdde927426e2531c9Paul Duffin */
167dd252788645e940eada959bdde927426e2531c9Paul Duffin
177dd252788645e940eada959bdde927426e2531c9Paul Duffinpackage com.google.common.reflect;
187dd252788645e940eada959bdde927426e2531c9Paul Duffin
197dd252788645e940eada959bdde927426e2531c9Paul Duffinimport static com.google.common.base.Preconditions.checkNotNull;
207dd252788645e940eada959bdde927426e2531c9Paul Duffin
217dd252788645e940eada959bdde927426e2531c9Paul Duffinimport com.google.common.annotations.Beta;
227dd252788645e940eada959bdde927426e2531c9Paul Duffinimport com.google.common.collect.ImmutableList;
237dd252788645e940eada959bdde927426e2531c9Paul Duffin
247dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.lang.annotation.Annotation;
257dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.lang.reflect.AccessibleObject;
267dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.lang.reflect.Constructor;
277dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.lang.reflect.GenericDeclaration;
287dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.lang.reflect.InvocationTargetException;
297dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.lang.reflect.Member;
307dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.lang.reflect.Method;
317dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.lang.reflect.Modifier;
327dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.lang.reflect.Type;
337dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.lang.reflect.TypeVariable;
340888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport java.util.Arrays;
357dd252788645e940eada959bdde927426e2531c9Paul Duffin
367dd252788645e940eada959bdde927426e2531c9Paul Duffinimport javax.annotation.Nullable;
377dd252788645e940eada959bdde927426e2531c9Paul Duffin
387dd252788645e940eada959bdde927426e2531c9Paul Duffin/**
397dd252788645e940eada959bdde927426e2531c9Paul Duffin * Wrapper around either a {@link Method} or a {@link Constructor}.
407dd252788645e940eada959bdde927426e2531c9Paul Duffin * Convenience API is provided to make common reflective operation easier to deal with,
417dd252788645e940eada959bdde927426e2531c9Paul Duffin * such as {@link #isPublic}, {@link #getParameters} etc.
427dd252788645e940eada959bdde927426e2531c9Paul Duffin *
437dd252788645e940eada959bdde927426e2531c9Paul Duffin * <p>In addition to convenience methods, {@link TypeToken#method} and {@link
447dd252788645e940eada959bdde927426e2531c9Paul Duffin * TypeToken#constructor} will resolve the type parameters of the method or constructor in the
457dd252788645e940eada959bdde927426e2531c9Paul Duffin * context of the owner type, which may be a subtype of the declaring class. For example:
467dd252788645e940eada959bdde927426e2531c9Paul Duffin *
470888a09821a98ac0680fad765217302858e70fa4Paul Duffin * <pre>   {@code
487dd252788645e940eada959bdde927426e2531c9Paul Duffin *   Method getMethod = List.class.getMethod("get", int.class);
497dd252788645e940eada959bdde927426e2531c9Paul Duffin *   Invokable<List<String>, ?> invokable = new TypeToken<List<String>>() {}.method(getMethod);
507dd252788645e940eada959bdde927426e2531c9Paul Duffin *   assertEquals(TypeToken.of(String.class), invokable.getReturnType()); // Not Object.class!
517dd252788645e940eada959bdde927426e2531c9Paul Duffin *   assertEquals(new TypeToken<List<String>>() {}, invokable.getOwnerType());}</pre>
527dd252788645e940eada959bdde927426e2531c9Paul Duffin *
537dd252788645e940eada959bdde927426e2531c9Paul Duffin * @param <T> the type that owns this method or constructor.
547dd252788645e940eada959bdde927426e2531c9Paul Duffin * @param <R> the return type of (or supertype thereof) the method or the declaring type of the
557dd252788645e940eada959bdde927426e2531c9Paul Duffin *            constructor.
567dd252788645e940eada959bdde927426e2531c9Paul Duffin * @author Ben Yu
577dd252788645e940eada959bdde927426e2531c9Paul Duffin * @since 14.0
587dd252788645e940eada959bdde927426e2531c9Paul Duffin */
597dd252788645e940eada959bdde927426e2531c9Paul Duffin@Beta
607dd252788645e940eada959bdde927426e2531c9Paul Duffinpublic abstract class Invokable<T, R> extends Element implements GenericDeclaration {
617dd252788645e940eada959bdde927426e2531c9Paul Duffin
627dd252788645e940eada959bdde927426e2531c9Paul Duffin  <M extends AccessibleObject & Member> Invokable(M member) {
637dd252788645e940eada959bdde927426e2531c9Paul Duffin    super(member);
647dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
657dd252788645e940eada959bdde927426e2531c9Paul Duffin
667dd252788645e940eada959bdde927426e2531c9Paul Duffin  /** Returns {@link Invokable} of {@code method}. */
677dd252788645e940eada959bdde927426e2531c9Paul Duffin  public static Invokable<?, Object> from(Method method) {
687dd252788645e940eada959bdde927426e2531c9Paul Duffin    return new MethodInvokable<Object>(method);
697dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
707dd252788645e940eada959bdde927426e2531c9Paul Duffin
717dd252788645e940eada959bdde927426e2531c9Paul Duffin  /** Returns {@link Invokable} of {@code constructor}. */
727dd252788645e940eada959bdde927426e2531c9Paul Duffin  public static <T> Invokable<T, T> from(Constructor<T> constructor) {
737dd252788645e940eada959bdde927426e2531c9Paul Duffin    return new ConstructorInvokable<T>(constructor);
747dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
757dd252788645e940eada959bdde927426e2531c9Paul Duffin
767dd252788645e940eada959bdde927426e2531c9Paul Duffin  /**
777dd252788645e940eada959bdde927426e2531c9Paul Duffin   * Returns {@code true} if this is an overridable method. Constructors, private, static or final
787dd252788645e940eada959bdde927426e2531c9Paul Duffin   * methods, or methods declared by final classes are not overridable.
797dd252788645e940eada959bdde927426e2531c9Paul Duffin   */
807dd252788645e940eada959bdde927426e2531c9Paul Duffin  public abstract boolean isOverridable();
817dd252788645e940eada959bdde927426e2531c9Paul Duffin
827dd252788645e940eada959bdde927426e2531c9Paul Duffin  /** Returns {@code true} if this was declared to take a variable number of arguments. */
837dd252788645e940eada959bdde927426e2531c9Paul Duffin  public abstract boolean isVarArgs();
847dd252788645e940eada959bdde927426e2531c9Paul Duffin
857dd252788645e940eada959bdde927426e2531c9Paul Duffin  /**
867dd252788645e940eada959bdde927426e2531c9Paul Duffin   * Invokes with {@code receiver} as 'this' and {@code args} passed to the underlying method
877dd252788645e940eada959bdde927426e2531c9Paul Duffin   * and returns the return value; or calls the underlying constructor with {@code args} and returns
887dd252788645e940eada959bdde927426e2531c9Paul Duffin   * the constructed instance.
897dd252788645e940eada959bdde927426e2531c9Paul Duffin   *
907dd252788645e940eada959bdde927426e2531c9Paul Duffin   * @throws IllegalAccessException if this {@code Constructor} object enforces Java language
917dd252788645e940eada959bdde927426e2531c9Paul Duffin   *         access control and the underlying method or constructor is inaccessible.
927dd252788645e940eada959bdde927426e2531c9Paul Duffin   * @throws IllegalArgumentException if the number of actual and formal parameters differ;
937dd252788645e940eada959bdde927426e2531c9Paul Duffin   *         if an unwrapping conversion for primitive arguments fails; or if, after possible
947dd252788645e940eada959bdde927426e2531c9Paul Duffin   *         unwrapping, a parameter value cannot be converted to the corresponding formal
957dd252788645e940eada959bdde927426e2531c9Paul Duffin   *         parameter type by a method invocation conversion.
967dd252788645e940eada959bdde927426e2531c9Paul Duffin   * @throws InvocationTargetException if the underlying method or constructor throws an exception.
977dd252788645e940eada959bdde927426e2531c9Paul Duffin   */
987dd252788645e940eada959bdde927426e2531c9Paul Duffin  // All subclasses are owned by us and we'll make sure to get the R type right.
997dd252788645e940eada959bdde927426e2531c9Paul Duffin  @SuppressWarnings("unchecked")
1000888a09821a98ac0680fad765217302858e70fa4Paul Duffin  public final R invoke(@Nullable T receiver, Object... args)
1010888a09821a98ac0680fad765217302858e70fa4Paul Duffin      throws InvocationTargetException, IllegalAccessException {
1027dd252788645e940eada959bdde927426e2531c9Paul Duffin    return (R) invokeInternal(receiver, checkNotNull(args));
1037dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
1047dd252788645e940eada959bdde927426e2531c9Paul Duffin
1057dd252788645e940eada959bdde927426e2531c9Paul Duffin  /** Returns the return type of this {@code Invokable}. */
1067dd252788645e940eada959bdde927426e2531c9Paul Duffin  // All subclasses are owned by us and we'll make sure to get the R type right.
1077dd252788645e940eada959bdde927426e2531c9Paul Duffin  @SuppressWarnings("unchecked")
1087dd252788645e940eada959bdde927426e2531c9Paul Duffin  public final TypeToken<? extends R> getReturnType() {
1097dd252788645e940eada959bdde927426e2531c9Paul Duffin    return (TypeToken<? extends R>) TypeToken.of(getGenericReturnType());
1107dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
1117dd252788645e940eada959bdde927426e2531c9Paul Duffin
1127dd252788645e940eada959bdde927426e2531c9Paul Duffin  /**
1137dd252788645e940eada959bdde927426e2531c9Paul Duffin   * Returns all declared parameters of this {@code Invokable}. Note that if this is a constructor
1147dd252788645e940eada959bdde927426e2531c9Paul Duffin   * of a non-static inner class, unlike {@link Constructor#getParameterTypes}, the hidden
1157dd252788645e940eada959bdde927426e2531c9Paul Duffin   * {@code this} parameter of the enclosing class is excluded from the returned parameters.
1167dd252788645e940eada959bdde927426e2531c9Paul Duffin   */
1177dd252788645e940eada959bdde927426e2531c9Paul Duffin  public final ImmutableList<Parameter> getParameters() {
1187dd252788645e940eada959bdde927426e2531c9Paul Duffin    Type[] parameterTypes = getGenericParameterTypes();
1197dd252788645e940eada959bdde927426e2531c9Paul Duffin    Annotation[][] annotations = getParameterAnnotations();
1207dd252788645e940eada959bdde927426e2531c9Paul Duffin    ImmutableList.Builder<Parameter> builder = ImmutableList.builder();
1217dd252788645e940eada959bdde927426e2531c9Paul Duffin    for (int i = 0; i < parameterTypes.length; i++) {
1220888a09821a98ac0680fad765217302858e70fa4Paul Duffin      builder.add(new Parameter(
1230888a09821a98ac0680fad765217302858e70fa4Paul Duffin          this, i, TypeToken.of(parameterTypes[i]), annotations[i]));
1247dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
1257dd252788645e940eada959bdde927426e2531c9Paul Duffin    return builder.build();
1267dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
1277dd252788645e940eada959bdde927426e2531c9Paul Duffin
1287dd252788645e940eada959bdde927426e2531c9Paul Duffin  /** Returns all declared exception types of this {@code Invokable}. */
1297dd252788645e940eada959bdde927426e2531c9Paul Duffin  public final ImmutableList<TypeToken<? extends Throwable>> getExceptionTypes() {
1307dd252788645e940eada959bdde927426e2531c9Paul Duffin    ImmutableList.Builder<TypeToken<? extends Throwable>> builder = ImmutableList.builder();
1317dd252788645e940eada959bdde927426e2531c9Paul Duffin    for (Type type : getGenericExceptionTypes()) {
1320888a09821a98ac0680fad765217302858e70fa4Paul Duffin       // getGenericExceptionTypes() will never return a type that's not exception
1337dd252788645e940eada959bdde927426e2531c9Paul Duffin      @SuppressWarnings("unchecked")
1340888a09821a98ac0680fad765217302858e70fa4Paul Duffin      TypeToken<? extends Throwable> exceptionType = (TypeToken<? extends Throwable>)
1350888a09821a98ac0680fad765217302858e70fa4Paul Duffin          TypeToken.of(type);
1367dd252788645e940eada959bdde927426e2531c9Paul Duffin      builder.add(exceptionType);
1377dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
1387dd252788645e940eada959bdde927426e2531c9Paul Duffin    return builder.build();
1397dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
1407dd252788645e940eada959bdde927426e2531c9Paul Duffin
1417dd252788645e940eada959bdde927426e2531c9Paul Duffin  /**
1427dd252788645e940eada959bdde927426e2531c9Paul Duffin   * Explicitly specifies the return type of this {@code Invokable}. For example:
1437dd252788645e940eada959bdde927426e2531c9Paul Duffin   * <pre>   {@code
1447dd252788645e940eada959bdde927426e2531c9Paul Duffin   *   Method factoryMethod = Person.class.getMethod("create");
1450888a09821a98ac0680fad765217302858e70fa4Paul Duffin   *   Invokable<?, Person> factory = Invokable.of(getNameMethod).returning(Person.class);}</pre>
1467dd252788645e940eada959bdde927426e2531c9Paul Duffin   */
1477dd252788645e940eada959bdde927426e2531c9Paul Duffin  public final <R1 extends R> Invokable<T, R1> returning(Class<R1> returnType) {
1487dd252788645e940eada959bdde927426e2531c9Paul Duffin    return returning(TypeToken.of(returnType));
1497dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
1507dd252788645e940eada959bdde927426e2531c9Paul Duffin
1517dd252788645e940eada959bdde927426e2531c9Paul Duffin  /** Explicitly specifies the return type of this {@code Invokable}. */
1527dd252788645e940eada959bdde927426e2531c9Paul Duffin  public final <R1 extends R> Invokable<T, R1> returning(TypeToken<R1> returnType) {
1537dd252788645e940eada959bdde927426e2531c9Paul Duffin    if (!returnType.isAssignableFrom(getReturnType())) {
1540888a09821a98ac0680fad765217302858e70fa4Paul Duffin      throw new IllegalArgumentException(
1550888a09821a98ac0680fad765217302858e70fa4Paul Duffin          "Invokable is known to return " + getReturnType() + ", not " + returnType);
1567dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
1570888a09821a98ac0680fad765217302858e70fa4Paul Duffin    @SuppressWarnings("unchecked") // guarded by previous check
1587dd252788645e940eada959bdde927426e2531c9Paul Duffin    Invokable<T, R1> specialized = (Invokable<T, R1>) this;
1597dd252788645e940eada959bdde927426e2531c9Paul Duffin    return specialized;
1607dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
1617dd252788645e940eada959bdde927426e2531c9Paul Duffin
1620888a09821a98ac0680fad765217302858e70fa4Paul Duffin  @SuppressWarnings("unchecked") // The declaring class is T's raw class, or one of its supertypes.
1630888a09821a98ac0680fad765217302858e70fa4Paul Duffin  @Override public final Class<? super T> getDeclaringClass() {
1647dd252788645e940eada959bdde927426e2531c9Paul Duffin    return (Class<? super T>) super.getDeclaringClass();
1657dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
1667dd252788645e940eada959bdde927426e2531c9Paul Duffin
1677dd252788645e940eada959bdde927426e2531c9Paul Duffin  /** Returns the type of {@code T}. */
1687dd252788645e940eada959bdde927426e2531c9Paul Duffin  // Overridden in TypeToken#method() and TypeToken#constructor()
1697dd252788645e940eada959bdde927426e2531c9Paul Duffin  @SuppressWarnings("unchecked") // The declaring class is T.
1700888a09821a98ac0680fad765217302858e70fa4Paul Duffin  @Override public TypeToken<T> getOwnerType() {
1717dd252788645e940eada959bdde927426e2531c9Paul Duffin    return (TypeToken<T>) TypeToken.of(getDeclaringClass());
1727dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
1737dd252788645e940eada959bdde927426e2531c9Paul Duffin
1747dd252788645e940eada959bdde927426e2531c9Paul Duffin  abstract Object invokeInternal(@Nullable Object receiver, Object[] args)
1757dd252788645e940eada959bdde927426e2531c9Paul Duffin      throws InvocationTargetException, IllegalAccessException;
1767dd252788645e940eada959bdde927426e2531c9Paul Duffin
1777dd252788645e940eada959bdde927426e2531c9Paul Duffin  abstract Type[] getGenericParameterTypes();
1787dd252788645e940eada959bdde927426e2531c9Paul Duffin
1797dd252788645e940eada959bdde927426e2531c9Paul Duffin  /** This should never return a type that's not a subtype of Throwable. */
1807dd252788645e940eada959bdde927426e2531c9Paul Duffin  abstract Type[] getGenericExceptionTypes();
1817dd252788645e940eada959bdde927426e2531c9Paul Duffin
1827dd252788645e940eada959bdde927426e2531c9Paul Duffin  abstract Annotation[][] getParameterAnnotations();
1837dd252788645e940eada959bdde927426e2531c9Paul Duffin
1847dd252788645e940eada959bdde927426e2531c9Paul Duffin  abstract Type getGenericReturnType();
1850888a09821a98ac0680fad765217302858e70fa4Paul Duffin
1867dd252788645e940eada959bdde927426e2531c9Paul Duffin  static class MethodInvokable<T> extends Invokable<T, Object> {
1877dd252788645e940eada959bdde927426e2531c9Paul Duffin
1880888a09821a98ac0680fad765217302858e70fa4Paul Duffin    final Method method;
1897dd252788645e940eada959bdde927426e2531c9Paul Duffin
1907dd252788645e940eada959bdde927426e2531c9Paul Duffin    MethodInvokable(Method method) {
1917dd252788645e940eada959bdde927426e2531c9Paul Duffin      super(method);
1927dd252788645e940eada959bdde927426e2531c9Paul Duffin      this.method = method;
1937dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
1947dd252788645e940eada959bdde927426e2531c9Paul Duffin
1950888a09821a98ac0680fad765217302858e70fa4Paul Duffin    @Override final Object invokeInternal(@Nullable Object receiver, Object[] args)
1967dd252788645e940eada959bdde927426e2531c9Paul Duffin        throws InvocationTargetException, IllegalAccessException {
1977dd252788645e940eada959bdde927426e2531c9Paul Duffin      return method.invoke(receiver, args);
1987dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
1997dd252788645e940eada959bdde927426e2531c9Paul Duffin
2000888a09821a98ac0680fad765217302858e70fa4Paul Duffin    @Override Type getGenericReturnType() {
2017dd252788645e940eada959bdde927426e2531c9Paul Duffin      return method.getGenericReturnType();
2027dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
2037dd252788645e940eada959bdde927426e2531c9Paul Duffin
2040888a09821a98ac0680fad765217302858e70fa4Paul Duffin    @Override Type[] getGenericParameterTypes() {
2057dd252788645e940eada959bdde927426e2531c9Paul Duffin      return method.getGenericParameterTypes();
2067dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
2077dd252788645e940eada959bdde927426e2531c9Paul Duffin
2080888a09821a98ac0680fad765217302858e70fa4Paul Duffin    @Override Type[] getGenericExceptionTypes() {
2097dd252788645e940eada959bdde927426e2531c9Paul Duffin      return method.getGenericExceptionTypes();
2107dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
2117dd252788645e940eada959bdde927426e2531c9Paul Duffin
2120888a09821a98ac0680fad765217302858e70fa4Paul Duffin    @Override final Annotation[][] getParameterAnnotations() {
2137dd252788645e940eada959bdde927426e2531c9Paul Duffin      return method.getParameterAnnotations();
2147dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
2157dd252788645e940eada959bdde927426e2531c9Paul Duffin
2160888a09821a98ac0680fad765217302858e70fa4Paul Duffin    @Override public final TypeVariable<?>[] getTypeParameters() {
2177dd252788645e940eada959bdde927426e2531c9Paul Duffin      return method.getTypeParameters();
2187dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
2197dd252788645e940eada959bdde927426e2531c9Paul Duffin
2207dd252788645e940eada959bdde927426e2531c9Paul Duffin    @Override public final boolean isOverridable() {
2217dd252788645e940eada959bdde927426e2531c9Paul Duffin      return  !(isFinal() || isPrivate() || isStatic()
2227dd252788645e940eada959bdde927426e2531c9Paul Duffin          || Modifier.isFinal(getDeclaringClass().getModifiers()));
2237dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
2247dd252788645e940eada959bdde927426e2531c9Paul Duffin
2257dd252788645e940eada959bdde927426e2531c9Paul Duffin    @Override public final boolean isVarArgs() {
2267dd252788645e940eada959bdde927426e2531c9Paul Duffin      return method.isVarArgs();
2277dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
2287dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
2297dd252788645e940eada959bdde927426e2531c9Paul Duffin
2307dd252788645e940eada959bdde927426e2531c9Paul Duffin  static class ConstructorInvokable<T> extends Invokable<T, T> {
2317dd252788645e940eada959bdde927426e2531c9Paul Duffin
2320888a09821a98ac0680fad765217302858e70fa4Paul Duffin    final Constructor<?> constructor;
2337dd252788645e940eada959bdde927426e2531c9Paul Duffin
2347dd252788645e940eada959bdde927426e2531c9Paul Duffin    ConstructorInvokable(Constructor<?> constructor) {
2357dd252788645e940eada959bdde927426e2531c9Paul Duffin      super(constructor);
2367dd252788645e940eada959bdde927426e2531c9Paul Duffin      this.constructor = constructor;
2377dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
2387dd252788645e940eada959bdde927426e2531c9Paul Duffin
2390888a09821a98ac0680fad765217302858e70fa4Paul Duffin    @Override final Object invokeInternal(@Nullable Object receiver, Object[] args)
2407dd252788645e940eada959bdde927426e2531c9Paul Duffin        throws InvocationTargetException, IllegalAccessException {
2417dd252788645e940eada959bdde927426e2531c9Paul Duffin      try {
2427dd252788645e940eada959bdde927426e2531c9Paul Duffin        return constructor.newInstance(args);
2437dd252788645e940eada959bdde927426e2531c9Paul Duffin      } catch (InstantiationException e) {
2447dd252788645e940eada959bdde927426e2531c9Paul Duffin        throw new RuntimeException(constructor + " failed.", e);
2457dd252788645e940eada959bdde927426e2531c9Paul Duffin      }
2467dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
2477dd252788645e940eada959bdde927426e2531c9Paul Duffin
2480888a09821a98ac0680fad765217302858e70fa4Paul Duffin    /** If the class is parameterized, such as ArrayList, this returns ArrayList<E>. */
2490888a09821a98ac0680fad765217302858e70fa4Paul Duffin    @Override Type getGenericReturnType() {
2500888a09821a98ac0680fad765217302858e70fa4Paul Duffin      Class<?> declaringClass = getDeclaringClass();
2510888a09821a98ac0680fad765217302858e70fa4Paul Duffin      TypeVariable<?>[] typeParams = declaringClass.getTypeParameters();
2520888a09821a98ac0680fad765217302858e70fa4Paul Duffin      if (typeParams.length > 0) {
2530888a09821a98ac0680fad765217302858e70fa4Paul Duffin        return Types.newParameterizedType(declaringClass, typeParams);
2540888a09821a98ac0680fad765217302858e70fa4Paul Duffin      } else {
2550888a09821a98ac0680fad765217302858e70fa4Paul Duffin        return declaringClass;
2560888a09821a98ac0680fad765217302858e70fa4Paul Duffin      }
2577dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
2587dd252788645e940eada959bdde927426e2531c9Paul Duffin
2590888a09821a98ac0680fad765217302858e70fa4Paul Duffin    @Override Type[] getGenericParameterTypes() {
2607dd252788645e940eada959bdde927426e2531c9Paul Duffin      Type[] types = constructor.getGenericParameterTypes();
2610888a09821a98ac0680fad765217302858e70fa4Paul Duffin      if (types.length > 0 && mayNeedHiddenThis()) {
2620888a09821a98ac0680fad765217302858e70fa4Paul Duffin        Class<?>[] rawParamTypes = constructor.getParameterTypes();
2630888a09821a98ac0680fad765217302858e70fa4Paul Duffin        if (types.length == rawParamTypes.length
2640888a09821a98ac0680fad765217302858e70fa4Paul Duffin            && rawParamTypes[0] == getDeclaringClass().getEnclosingClass()) {
2657dd252788645e940eada959bdde927426e2531c9Paul Duffin          // first parameter is the hidden 'this'
2663ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin          return Arrays.copyOfRange(types, 1, types.length);
2677dd252788645e940eada959bdde927426e2531c9Paul Duffin        }
2687dd252788645e940eada959bdde927426e2531c9Paul Duffin      }
2697dd252788645e940eada959bdde927426e2531c9Paul Duffin      return types;
2707dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
2717dd252788645e940eada959bdde927426e2531c9Paul Duffin
2720888a09821a98ac0680fad765217302858e70fa4Paul Duffin    @Override Type[] getGenericExceptionTypes() {
2737dd252788645e940eada959bdde927426e2531c9Paul Duffin      return constructor.getGenericExceptionTypes();
2747dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
2757dd252788645e940eada959bdde927426e2531c9Paul Duffin
2760888a09821a98ac0680fad765217302858e70fa4Paul Duffin    @Override final Annotation[][] getParameterAnnotations() {
2777dd252788645e940eada959bdde927426e2531c9Paul Duffin      return constructor.getParameterAnnotations();
2787dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
2797dd252788645e940eada959bdde927426e2531c9Paul Duffin
2800888a09821a98ac0680fad765217302858e70fa4Paul Duffin    /**
2810888a09821a98ac0680fad765217302858e70fa4Paul Duffin     * {@inheritDoc}
2820888a09821a98ac0680fad765217302858e70fa4Paul Duffin     *
2830888a09821a98ac0680fad765217302858e70fa4Paul Duffin     * {@code [<E>]} will be returned for ArrayList's constructor. When both the class and the
2840888a09821a98ac0680fad765217302858e70fa4Paul Duffin     * constructor have type parameters, the class parameters are prepended before those of the
2850888a09821a98ac0680fad765217302858e70fa4Paul Duffin     * constructor's. This is an arbitrary rule since no existing language spec mandates one way or
2860888a09821a98ac0680fad765217302858e70fa4Paul Duffin     * the other. From the declaration syntax, the class type parameter appears first, but the
2870888a09821a98ac0680fad765217302858e70fa4Paul Duffin     * call syntax may show up in opposite order such as {@code new <A>Foo<B>()}.
2880888a09821a98ac0680fad765217302858e70fa4Paul Duffin     */
2890888a09821a98ac0680fad765217302858e70fa4Paul Duffin    @Override public final TypeVariable<?>[] getTypeParameters() {
2900888a09821a98ac0680fad765217302858e70fa4Paul Duffin      TypeVariable<?>[] declaredByClass = getDeclaringClass().getTypeParameters();
2910888a09821a98ac0680fad765217302858e70fa4Paul Duffin      TypeVariable<?>[] declaredByConstructor = constructor.getTypeParameters();
2920888a09821a98ac0680fad765217302858e70fa4Paul Duffin      TypeVariable<?>[] result =
2930888a09821a98ac0680fad765217302858e70fa4Paul Duffin          new TypeVariable<?>[declaredByClass.length + declaredByConstructor.length];
2940888a09821a98ac0680fad765217302858e70fa4Paul Duffin      System.arraycopy(declaredByClass, 0, result, 0, declaredByClass.length);
2950888a09821a98ac0680fad765217302858e70fa4Paul Duffin      System.arraycopy(
2960888a09821a98ac0680fad765217302858e70fa4Paul Duffin          declaredByConstructor, 0,
2970888a09821a98ac0680fad765217302858e70fa4Paul Duffin          result, declaredByClass.length,
2980888a09821a98ac0680fad765217302858e70fa4Paul Duffin          declaredByConstructor.length);
2990888a09821a98ac0680fad765217302858e70fa4Paul Duffin      return result;
3007dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
3017dd252788645e940eada959bdde927426e2531c9Paul Duffin
3020888a09821a98ac0680fad765217302858e70fa4Paul Duffin    @Override public final boolean isOverridable() {
3037dd252788645e940eada959bdde927426e2531c9Paul Duffin      return false;
3047dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
3057dd252788645e940eada959bdde927426e2531c9Paul Duffin
3067dd252788645e940eada959bdde927426e2531c9Paul Duffin    @Override public final boolean isVarArgs() {
3077dd252788645e940eada959bdde927426e2531c9Paul Duffin      return constructor.isVarArgs();
3087dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
3090888a09821a98ac0680fad765217302858e70fa4Paul Duffin
3100888a09821a98ac0680fad765217302858e70fa4Paul Duffin    private boolean mayNeedHiddenThis() {
3110888a09821a98ac0680fad765217302858e70fa4Paul Duffin      Class<?> declaringClass = constructor.getDeclaringClass();
3120888a09821a98ac0680fad765217302858e70fa4Paul Duffin      if (declaringClass.getEnclosingConstructor() != null) {
3130888a09821a98ac0680fad765217302858e70fa4Paul Duffin        // Enclosed in a constructor, needs hidden this
3140888a09821a98ac0680fad765217302858e70fa4Paul Duffin        return true;
3150888a09821a98ac0680fad765217302858e70fa4Paul Duffin      }
3160888a09821a98ac0680fad765217302858e70fa4Paul Duffin      Method enclosingMethod = declaringClass.getEnclosingMethod();
3170888a09821a98ac0680fad765217302858e70fa4Paul Duffin      if (enclosingMethod != null) {
3180888a09821a98ac0680fad765217302858e70fa4Paul Duffin        // Enclosed in a method, if it's not static, must need hidden this.
3190888a09821a98ac0680fad765217302858e70fa4Paul Duffin        return !Modifier.isStatic(enclosingMethod.getModifiers());
3200888a09821a98ac0680fad765217302858e70fa4Paul Duffin      } else {
3210888a09821a98ac0680fad765217302858e70fa4Paul Duffin        // Strictly, this doesn't necessarily indicate a hidden 'this' in the case of
3220888a09821a98ac0680fad765217302858e70fa4Paul Duffin        // static initializer. But there seems no way to tell in that case. :(
3230888a09821a98ac0680fad765217302858e70fa4Paul Duffin        // This may cause issues when an anonymous class is created inside a static initializer,
3240888a09821a98ac0680fad765217302858e70fa4Paul Duffin        // and the class's constructor's first parameter happens to be the enclosing class.
3250888a09821a98ac0680fad765217302858e70fa4Paul Duffin        // In such case, we may mistakenly think that the class is within a non-static context
3260888a09821a98ac0680fad765217302858e70fa4Paul Duffin        // and the first parameter is the hidden 'this'.
3270888a09821a98ac0680fad765217302858e70fa4Paul Duffin        return declaringClass.getEnclosingClass() != null
3280888a09821a98ac0680fad765217302858e70fa4Paul Duffin            && !Modifier.isStatic(declaringClass.getModifiers());
3290888a09821a98ac0680fad765217302858e70fa4Paul Duffin      }
3300888a09821a98ac0680fad765217302858e70fa4Paul Duffin    }
3317dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
3327dd252788645e940eada959bdde927426e2531c9Paul Duffin}
333