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}