• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.Constructor;
26 import java.lang.reflect.InvocationTargetException;
27 import java.lang.reflect.Member;
28 import java.lang.reflect.Method;
29 import java.lang.reflect.Modifier;
30 import java.lang.reflect.Type;
31 import java.lang.reflect.TypeVariable;
32 import java.util.Arrays;
33 import javax.annotation.CheckForNull;
34 import org.checkerframework.checker.nullness.qual.Nullable;
35 
36 /**
37  * Wrapper around either a {@link Method} or a {@link Constructor}. Convenience API is provided to
38  * make common reflective operation easier to deal with, such as {@link #isPublic}, {@link
39  * #getParameters} etc.
40  *
41  * <p>In addition to convenience methods, {@link TypeToken#method} and {@link TypeToken#constructor}
42  * will resolve the type parameters of the method or constructor in the context of the owner type,
43  * which may be a subtype of the declaring class. For example:
44  *
45  * <pre>{@code
46  * Method getMethod = List.class.getMethod("get", int.class);
47  * Invokable<List<String>, ?> invokable = new TypeToken<List<String>>() {}.method(getMethod);
48  * assertEquals(TypeToken.of(String.class), invokable.getReturnType()); // Not Object.class!
49  * assertEquals(new TypeToken<List<String>>() {}, invokable.getOwnerType());
50  * }</pre>
51  *
52  * <p><b>Note:</b> earlier versions of this class inherited from {@link
53  * java.lang.reflect.AccessibleObject AccessibleObject} and {@link
54  * java.lang.reflect.GenericDeclaration GenericDeclaration}. Since version 31.0 that is no longer
55  * the case. However, most methods from those types are present with the same signature in this
56  * class.
57  *
58  * @param <T> the type that owns this method or constructor.
59  * @param <R> the return type of (or supertype thereof) the method or the declaring type of the
60  *     constructor.
61  * @author Ben Yu
62  * @since 14.0 (no longer implements {@link AccessibleObject} or {@code GenericDeclaration} since
63  *     31.0)
64  */
65 @Beta
66 @ElementTypesAreNonnullByDefault
67 public abstract class Invokable<T, R> implements AnnotatedElement, Member {
68   private final AccessibleObject accessibleObject;
69   private final Member member;
70 
Invokable(M member)71   <M extends AccessibleObject & Member> Invokable(M member) {
72     checkNotNull(member);
73     this.accessibleObject = member;
74     this.member = member;
75   }
76 
77   /** Returns {@link Invokable} of {@code method}. */
from(Method method)78   public static Invokable<?, Object> from(Method method) {
79     return new MethodInvokable<>(method);
80   }
81 
82   /** Returns {@link Invokable} of {@code constructor}. */
from(Constructor<T> constructor)83   public static <T> Invokable<T, T> from(Constructor<T> constructor) {
84     return new ConstructorInvokable<T>(constructor);
85   }
86 
87   @Override
isAnnotationPresent(Class<? extends Annotation> annotationClass)88   public final boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
89     return accessibleObject.isAnnotationPresent(annotationClass);
90   }
91 
92   @Override
93   @CheckForNull
getAnnotation(Class<A> annotationClass)94   public final <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
95     return accessibleObject.getAnnotation(annotationClass);
96   }
97 
98   @Override
getAnnotations()99   public final Annotation[] getAnnotations() {
100     return accessibleObject.getAnnotations();
101   }
102 
103   @Override
getDeclaredAnnotations()104   public final Annotation[] getDeclaredAnnotations() {
105     return accessibleObject.getDeclaredAnnotations();
106   }
107 
108   // We ought to be able to implement GenericDeclaration instead its parent AnnotatedElement.
109   // That would give us this method declaration. But for some reason, implementing
110   // GenericDeclaration leads to weird errors in Android tests:
111   // IncompatibleClassChangeError: interface not implemented
112   /** See {@link java.lang.reflect.GenericDeclaration#getTypeParameters()}. */
getTypeParameters()113   public abstract TypeVariable<?>[] getTypeParameters();
114 
115   /** See {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)}. */
setAccessible(boolean flag)116   public final void setAccessible(boolean flag) {
117     accessibleObject.setAccessible(flag);
118   }
119 
120   /** See {@link java.lang.reflect.AccessibleObject#trySetAccessible()}. */
trySetAccessible()121   public final boolean trySetAccessible() {
122     // We can't call accessibleObject.trySetAccessible since that was added in Java 9 and this code
123     // should work on Java 8. So we emulate it this way.
124     try {
125       accessibleObject.setAccessible(true);
126       return true;
127     } catch (RuntimeException e) {
128       return false;
129     }
130   }
131 
132   /** See {@link java.lang.reflect.AccessibleObject#isAccessible()}. */
isAccessible()133   public final boolean isAccessible() {
134     return accessibleObject.isAccessible();
135   }
136 
137   @Override
getName()138   public final String getName() {
139     return member.getName();
140   }
141 
142   @Override
getModifiers()143   public final int getModifiers() {
144     return member.getModifiers();
145   }
146 
147   @Override
isSynthetic()148   public final boolean isSynthetic() {
149     return member.isSynthetic();
150   }
151 
152   /** Returns true if the element is public. */
isPublic()153   public final boolean isPublic() {
154     return Modifier.isPublic(getModifiers());
155   }
156 
157   /** Returns true if the element is protected. */
isProtected()158   public final boolean isProtected() {
159     return Modifier.isProtected(getModifiers());
160   }
161 
162   /** Returns true if the element is package-private. */
isPackagePrivate()163   public final boolean isPackagePrivate() {
164     return !isPrivate() && !isPublic() && !isProtected();
165   }
166 
167   /** Returns true if the element is private. */
isPrivate()168   public final boolean isPrivate() {
169     return Modifier.isPrivate(getModifiers());
170   }
171 
172   /** Returns true if the element is static. */
isStatic()173   public final boolean isStatic() {
174     return Modifier.isStatic(getModifiers());
175   }
176 
177   /**
178    * Returns {@code true} if this method is final, per {@code Modifier.isFinal(getModifiers())}.
179    *
180    * <p>Note that a method may still be effectively "final", or non-overridable when it has no
181    * {@code final} keyword. For example, it could be private, or it could be declared by a final
182    * class. To tell whether a method is overridable, use {@link Invokable#isOverridable}.
183    */
isFinal()184   public final boolean isFinal() {
185     return Modifier.isFinal(getModifiers());
186   }
187 
188   /** Returns true if the method is abstract. */
isAbstract()189   public final boolean isAbstract() {
190     return Modifier.isAbstract(getModifiers());
191   }
192 
193   /** Returns true if the element is native. */
isNative()194   public final boolean isNative() {
195     return Modifier.isNative(getModifiers());
196   }
197 
198   /** Returns true if the method is synchronized. */
isSynchronized()199   public final boolean isSynchronized() {
200     return Modifier.isSynchronized(getModifiers());
201   }
202 
203   /** Returns true if the field is volatile. */
isVolatile()204   final boolean isVolatile() {
205     return Modifier.isVolatile(getModifiers());
206   }
207 
208   /** Returns true if the field is transient. */
isTransient()209   final boolean isTransient() {
210     return Modifier.isTransient(getModifiers());
211   }
212 
213   @Override
equals(@heckForNull Object obj)214   public boolean equals(@CheckForNull Object obj) {
215     if (obj instanceof Invokable) {
216       Invokable<?, ?> that = (Invokable<?, ?>) obj;
217       return getOwnerType().equals(that.getOwnerType()) && member.equals(that.member);
218     }
219     return false;
220   }
221 
222   @Override
hashCode()223   public int hashCode() {
224     return member.hashCode();
225   }
226 
227   @Override
toString()228   public String toString() {
229     return member.toString();
230   }
231 
232   /**
233    * Returns {@code true} if this is an overridable method. Constructors, private, static or final
234    * methods, or methods declared by final classes are not overridable.
235    */
isOverridable()236   public abstract boolean isOverridable();
237 
238   /** Returns {@code true} if this was declared to take a variable number of arguments. */
isVarArgs()239   public abstract boolean isVarArgs();
240 
241   /**
242    * Invokes with {@code receiver} as 'this' and {@code args} passed to the underlying method and
243    * returns the return value; or calls the underlying constructor with {@code args} and returns the
244    * constructed instance.
245    *
246    * @throws IllegalAccessException if this {@code Constructor} object enforces Java language access
247    *     control and the underlying method or constructor is inaccessible.
248    * @throws IllegalArgumentException if the number of actual and formal parameters differ; if an
249    *     unwrapping conversion for primitive arguments fails; or if, after possible unwrapping, a
250    *     parameter value cannot be converted to the corresponding formal parameter type by a method
251    *     invocation conversion.
252    * @throws InvocationTargetException if the underlying method or constructor throws an exception.
253    */
254   // All subclasses are owned by us and we'll make sure to get the R type right, including nullness.
255   @SuppressWarnings({"unchecked", "nullness"})
256   @CanIgnoreReturnValue
257   @CheckForNull
invoke(@heckForNull T receiver, @Nullable Object... args)258   public final R invoke(@CheckForNull T receiver, @Nullable Object... args)
259       throws InvocationTargetException, IllegalAccessException {
260     return (R) invokeInternal(receiver, checkNotNull(args));
261   }
262 
263   /** Returns the return type of this {@code Invokable}. */
264   // All subclasses are owned by us and we'll make sure to get the R type right.
265   @SuppressWarnings("unchecked")
getReturnType()266   public final TypeToken<? extends R> getReturnType() {
267     return (TypeToken<? extends R>) TypeToken.of(getGenericReturnType());
268   }
269 
270   /**
271    * Returns all declared parameters of this {@code Invokable}. Note that if this is a constructor
272    * of a non-static inner class, unlike {@link Constructor#getParameterTypes}, the hidden {@code
273    * this} parameter of the enclosing class is excluded from the returned parameters.
274    */
getParameters()275   public final ImmutableList<Parameter> getParameters() {
276     Type[] parameterTypes = getGenericParameterTypes();
277     Annotation[][] annotations = getParameterAnnotations();
278     ImmutableList.Builder<Parameter> builder = ImmutableList.builder();
279     for (int i = 0; i < parameterTypes.length; i++) {
280       builder.add(new Parameter(this, i, TypeToken.of(parameterTypes[i]), annotations[i]));
281     }
282     return builder.build();
283   }
284 
285   /** Returns all declared exception types of this {@code Invokable}. */
getExceptionTypes()286   public final ImmutableList<TypeToken<? extends Throwable>> getExceptionTypes() {
287     ImmutableList.Builder<TypeToken<? extends Throwable>> builder = ImmutableList.builder();
288     for (Type type : getGenericExceptionTypes()) {
289       // getGenericExceptionTypes() will never return a type that's not exception
290       @SuppressWarnings("unchecked")
291       TypeToken<? extends Throwable> exceptionType =
292           (TypeToken<? extends Throwable>) TypeToken.of(type);
293       builder.add(exceptionType);
294     }
295     return builder.build();
296   }
297 
298   /**
299    * Explicitly specifies the return type of this {@code Invokable}. For example:
300    *
301    * <pre>{@code
302    * Method factoryMethod = Person.class.getMethod("create");
303    * Invokable<?, Person> factory = Invokable.of(getNameMethod).returning(Person.class);
304    * }</pre>
305    */
returning(Class<R1> returnType)306   public final <R1 extends R> Invokable<T, R1> returning(Class<R1> returnType) {
307     return returning(TypeToken.of(returnType));
308   }
309 
310   /** Explicitly specifies the return type of this {@code Invokable}. */
returning(TypeToken<R1> returnType)311   public final <R1 extends R> Invokable<T, R1> returning(TypeToken<R1> returnType) {
312     if (!returnType.isSupertypeOf(getReturnType())) {
313       throw new IllegalArgumentException(
314           "Invokable is known to return " + getReturnType() + ", not " + returnType);
315     }
316     @SuppressWarnings("unchecked") // guarded by previous check
317     Invokable<T, R1> specialized = (Invokable<T, R1>) this;
318     return specialized;
319   }
320 
321   @SuppressWarnings("unchecked") // The declaring class is T's raw class, or one of its supertypes.
322   @Override
getDeclaringClass()323   public final Class<? super T> getDeclaringClass() {
324     return (Class<? super T>) member.getDeclaringClass();
325   }
326 
327   /** Returns the type of {@code T}. */
328   // Overridden in TypeToken#method() and TypeToken#constructor()
329   @SuppressWarnings("unchecked") // The declaring class is T.
getOwnerType()330   public TypeToken<T> getOwnerType() {
331     return (TypeToken<T>) TypeToken.of(getDeclaringClass());
332   }
333 
334   @CheckForNull
invokeInternal(@heckForNull Object receiver, @Nullable Object[] args)335   abstract Object invokeInternal(@CheckForNull Object receiver, @Nullable Object[] args)
336       throws InvocationTargetException, IllegalAccessException;
337 
getGenericParameterTypes()338   abstract Type[] getGenericParameterTypes();
339 
340   /** This should never return a type that's not a subtype of Throwable. */
getGenericExceptionTypes()341   abstract Type[] getGenericExceptionTypes();
342 
getParameterAnnotations()343   abstract Annotation[][] getParameterAnnotations();
344 
getGenericReturnType()345   abstract Type getGenericReturnType();
346 
347   static class MethodInvokable<T> extends Invokable<T, Object> {
348 
349     final Method method;
350 
MethodInvokable(Method method)351     MethodInvokable(Method method) {
352       super(method);
353       this.method = method;
354     }
355 
356     @Override
357     @CheckForNull
invokeInternal(@heckForNull Object receiver, @Nullable Object[] args)358     final Object invokeInternal(@CheckForNull Object receiver, @Nullable Object[] args)
359         throws InvocationTargetException, IllegalAccessException {
360       return method.invoke(receiver, args);
361     }
362 
363     @Override
getGenericReturnType()364     Type getGenericReturnType() {
365       return method.getGenericReturnType();
366     }
367 
368     @Override
getGenericParameterTypes()369     Type[] getGenericParameterTypes() {
370       return method.getGenericParameterTypes();
371     }
372 
373     @Override
getGenericExceptionTypes()374     Type[] getGenericExceptionTypes() {
375       return method.getGenericExceptionTypes();
376     }
377 
378     @Override
getParameterAnnotations()379     final Annotation[][] getParameterAnnotations() {
380       return method.getParameterAnnotations();
381     }
382 
383     @Override
getTypeParameters()384     public final TypeVariable<?>[] getTypeParameters() {
385       return method.getTypeParameters();
386     }
387 
388     @Override
isOverridable()389     public final boolean isOverridable() {
390       return !(isFinal()
391           || isPrivate()
392           || isStatic()
393           || Modifier.isFinal(getDeclaringClass().getModifiers()));
394     }
395 
396     @Override
isVarArgs()397     public final boolean isVarArgs() {
398       return method.isVarArgs();
399     }
400   }
401 
402   static class ConstructorInvokable<T> extends Invokable<T, T> {
403 
404     final Constructor<?> constructor;
405 
ConstructorInvokable(Constructor<?> constructor)406     ConstructorInvokable(Constructor<?> constructor) {
407       super(constructor);
408       this.constructor = constructor;
409     }
410 
411     @Override
invokeInternal(@heckForNull Object receiver, @Nullable Object[] args)412     final Object invokeInternal(@CheckForNull Object receiver, @Nullable Object[] args)
413         throws InvocationTargetException, IllegalAccessException {
414       try {
415         return constructor.newInstance(args);
416       } catch (InstantiationException e) {
417         throw new RuntimeException(constructor + " failed.", e);
418       }
419     }
420 
421     /**
422      * If the class is parameterized, such as {@link java.util.ArrayList ArrayList}, this returns
423      * {@code ArrayList<E>}.
424      */
425     @Override
getGenericReturnType()426     Type getGenericReturnType() {
427       Class<?> declaringClass = getDeclaringClass();
428       TypeVariable<?>[] typeParams = declaringClass.getTypeParameters();
429       if (typeParams.length > 0) {
430         return Types.newParameterizedType(declaringClass, typeParams);
431       } else {
432         return declaringClass;
433       }
434     }
435 
436     @Override
getGenericParameterTypes()437     Type[] getGenericParameterTypes() {
438       Type[] types = constructor.getGenericParameterTypes();
439       if (types.length > 0 && mayNeedHiddenThis()) {
440         Class<?>[] rawParamTypes = constructor.getParameterTypes();
441         if (types.length == rawParamTypes.length
442             && rawParamTypes[0] == getDeclaringClass().getEnclosingClass()) {
443           // first parameter is the hidden 'this'
444           return Arrays.copyOfRange(types, 1, types.length);
445         }
446       }
447       return types;
448     }
449 
450     @Override
getGenericExceptionTypes()451     Type[] getGenericExceptionTypes() {
452       return constructor.getGenericExceptionTypes();
453     }
454 
455     @Override
getParameterAnnotations()456     final Annotation[][] getParameterAnnotations() {
457       return constructor.getParameterAnnotations();
458     }
459 
460     /**
461      * {@inheritDoc}
462      *
463      * <p>{@code [<E>]} will be returned for ArrayList's constructor. When both the class and the
464      * constructor have type parameters, the class parameters are prepended before those of the
465      * constructor's. This is an arbitrary rule since no existing language spec mandates one way or
466      * the other. From the declaration syntax, the class type parameter appears first, but the call
467      * syntax may show up in opposite order such as {@code new <A>Foo<B>()}.
468      */
469     @Override
getTypeParameters()470     public final TypeVariable<?>[] getTypeParameters() {
471       TypeVariable<?>[] declaredByClass = getDeclaringClass().getTypeParameters();
472       TypeVariable<?>[] declaredByConstructor = constructor.getTypeParameters();
473       TypeVariable<?>[] result =
474           new TypeVariable<?>[declaredByClass.length + declaredByConstructor.length];
475       System.arraycopy(declaredByClass, 0, result, 0, declaredByClass.length);
476       System.arraycopy(
477           declaredByConstructor, 0, result, declaredByClass.length, declaredByConstructor.length);
478       return result;
479     }
480 
481     @Override
isOverridable()482     public final boolean isOverridable() {
483       return false;
484     }
485 
486     @Override
isVarArgs()487     public final boolean isVarArgs() {
488       return constructor.isVarArgs();
489     }
490 
mayNeedHiddenThis()491     private boolean mayNeedHiddenThis() {
492       Class<?> declaringClass = constructor.getDeclaringClass();
493       if (declaringClass.getEnclosingConstructor() != null) {
494         // Enclosed in a constructor, needs hidden this
495         return true;
496       }
497       Method enclosingMethod = declaringClass.getEnclosingMethod();
498       if (enclosingMethod != null) {
499         // Enclosed in a method, if it's not static, must need hidden this.
500         return !Modifier.isStatic(enclosingMethod.getModifiers());
501       } else {
502         // Strictly, this doesn't necessarily indicate a hidden 'this' in the case of
503         // static initializer. But there seems no way to tell in that case. :(
504         // This may cause issues when an anonymous class is created inside a static initializer,
505         // and the class's constructor's first parameter happens to be the enclosing class.
506         // In such case, we may mistakenly think that the class is within a non-static context
507         // and the first parameter is the hidden 'this'.
508         return declaringClass.getEnclosingClass() != null
509             && !Modifier.isStatic(declaringClass.getModifiers());
510       }
511     }
512   }
513 }
514