1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.google.common.reflect;
18
19 import static com.google.common.base.Preconditions.checkNotNull;
20
21 import com.google.common.annotations.Beta;
22 import com.google.common.collect.ImmutableList;
23
24 import java.lang.annotation.Annotation;
25 import java.lang.reflect.AccessibleObject;
26 import java.lang.reflect.Constructor;
27 import java.lang.reflect.GenericDeclaration;
28 import java.lang.reflect.InvocationTargetException;
29 import java.lang.reflect.Member;
30 import java.lang.reflect.Method;
31 import java.lang.reflect.Modifier;
32 import java.lang.reflect.Type;
33 import java.lang.reflect.TypeVariable;
34 import java.util.Arrays;
35
36 import javax.annotation.Nullable;
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59 @Beta
60 public abstract class Invokable<T, R> extends Element implements GenericDeclaration {
61
62 <M extends AccessibleObject & Member> Invokable(M member) {
63 super(member);
64 }
65
66
67 public static Invokable<?, Object> from(Method method) {
68 return new MethodInvokable<Object>(method);
69 }
70
71
72 public static <T> Invokable<T, T> from(Constructor<T> constructor) {
73 return new ConstructorInvokable<T>(constructor);
74 }
75
76
77
78
79
80 public abstract boolean isOverridable();
81
82
83 public abstract boolean isVarArgs();
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99 @SuppressWarnings("unchecked")
100 public final R invoke(@Nullable T receiver, Object... args)
101 throws InvocationTargetException, IllegalAccessException {
102 return (R) invokeInternal(receiver, checkNotNull(args));
103 }
104
105
106
107 @SuppressWarnings("unchecked")
108 public final TypeToken<? extends R> getReturnType() {
109 return (TypeToken<? extends R>) TypeToken.of(getGenericReturnType());
110 }
111
112
113
114
115
116
117 public final ImmutableList<Parameter> getParameters() {
118 Type[] parameterTypes = getGenericParameterTypes();
119 Annotation[][] annotations = getParameterAnnotations();
120 ImmutableList.Builder<Parameter> builder = ImmutableList.builder();
121 for (int i = 0; i < parameterTypes.length; i++) {
122 builder.add(new Parameter(
123 this, i, TypeToken.of(parameterTypes[i]), annotations[i]));
124 }
125 return builder.build();
126 }
127
128
129 public final ImmutableList<TypeToken<? extends Throwable>> getExceptionTypes() {
130 ImmutableList.Builder<TypeToken<? extends Throwable>> builder = ImmutableList.builder();
131 for (Type type : getGenericExceptionTypes()) {
132
133 @SuppressWarnings("unchecked")
134 TypeToken<? extends Throwable> exceptionType = (TypeToken<? extends Throwable>)
135 TypeToken.of(type);
136 builder.add(exceptionType);
137 }
138 return builder.build();
139 }
140
141
142
143
144
145
146
147 public final <R1 extends R> Invokable<T, R1> returning(Class<R1> returnType) {
148 return returning(TypeToken.of(returnType));
149 }
150
151
152 public final <R1 extends R> Invokable<T, R1> returning(TypeToken<R1> returnType) {
153 if (!returnType.isAssignableFrom(getReturnType())) {
154 throw new IllegalArgumentException(
155 "Invokable is known to return " + getReturnType() + ", not " + returnType);
156 }
157 @SuppressWarnings("unchecked")
158 Invokable<T, R1> specialized = (Invokable<T, R1>) this;
159 return specialized;
160 }
161
162 @SuppressWarnings("unchecked")
163 @Override public final Class<? super T> getDeclaringClass() {
164 return (Class<? super T>) super.getDeclaringClass();
165 }
166
167
168
169 @SuppressWarnings("unchecked")
170 @Override public TypeToken<T> getOwnerType() {
171 return (TypeToken<T>) TypeToken.of(getDeclaringClass());
172 }
173
174 abstract Object invokeInternal(@Nullable Object receiver, Object[] args)
175 throws InvocationTargetException, IllegalAccessException;
176
177 abstract Type[] getGenericParameterTypes();
178
179
180 abstract Type[] getGenericExceptionTypes();
181
182 abstract Annotation[][] getParameterAnnotations();
183
184 abstract Type getGenericReturnType();
185
186 static class MethodInvokable<T> extends Invokable<T, Object> {
187
188 final Method method;
189
190 MethodInvokable(Method method) {
191 super(method);
192 this.method = method;
193 }
194
195 @Override final Object invokeInternal(@Nullable Object receiver, Object[] args)
196 throws InvocationTargetException, IllegalAccessException {
197 return method.invoke(receiver, args);
198 }
199
200 @Override Type getGenericReturnType() {
201 return method.getGenericReturnType();
202 }
203
204 @Override Type[] getGenericParameterTypes() {
205 return method.getGenericParameterTypes();
206 }
207
208 @Override Type[] getGenericExceptionTypes() {
209 return method.getGenericExceptionTypes();
210 }
211
212 @Override final Annotation[][] getParameterAnnotations() {
213 return method.getParameterAnnotations();
214 }
215
216 @Override public final TypeVariable<?>[] getTypeParameters() {
217 return method.getTypeParameters();
218 }
219
220 @Override public final boolean isOverridable() {
221 return !(isFinal() || isPrivate() || isStatic()
222 || Modifier.isFinal(getDeclaringClass().getModifiers()));
223 }
224
225 @Override public final boolean isVarArgs() {
226 return method.isVarArgs();
227 }
228 }
229
230 static class ConstructorInvokable<T> extends Invokable<T, T> {
231
232 final Constructor<?> constructor;
233
234 ConstructorInvokable(Constructor<?> constructor) {
235 super(constructor);
236 this.constructor = constructor;
237 }
238
239 @Override final Object invokeInternal(@Nullable Object receiver, Object[] args)
240 throws InvocationTargetException, IllegalAccessException {
241 try {
242 return constructor.newInstance(args);
243 } catch (InstantiationException e) {
244 throw new RuntimeException(constructor + " failed.", e);
245 }
246 }
247
248
249 @Override Type getGenericReturnType() {
250 Class<?> declaringClass = getDeclaringClass();
251 TypeVariable<?>[] typeParams = declaringClass.getTypeParameters();
252 if (typeParams.length > 0) {
253 return Types.newParameterizedType(declaringClass, typeParams);
254 } else {
255 return declaringClass;
256 }
257 }
258
259 @Override Type[] getGenericParameterTypes() {
260 Type[] types = constructor.getGenericParameterTypes();
261 if (types.length > 0 && mayNeedHiddenThis()) {
262 Class<?>[] rawParamTypes = constructor.getParameterTypes();
263 if (types.length == rawParamTypes.length
264 && rawParamTypes[0] == getDeclaringClass().getEnclosingClass()) {
265
266 return Arrays.copyOfRange(types, 1, types.length);
267 }
268 }
269 return types;
270 }
271
272 @Override Type[] getGenericExceptionTypes() {
273 return constructor.getGenericExceptionTypes();
274 }
275
276 @Override final Annotation[][] getParameterAnnotations() {
277 return constructor.getParameterAnnotations();
278 }
279
280
281
282
283
284
285
286
287
288
289 @Override public final TypeVariable<?>[] getTypeParameters() {
290 TypeVariable<?>[] declaredByClass = getDeclaringClass().getTypeParameters();
291 TypeVariable<?>[] declaredByConstructor = constructor.getTypeParameters();
292 TypeVariable<?>[] result =
293 new TypeVariable<?>[declaredByClass.length + declaredByConstructor.length];
294 System.arraycopy(declaredByClass, 0, result, 0, declaredByClass.length);
295 System.arraycopy(
296 declaredByConstructor, 0,
297 result, declaredByClass.length,
298 declaredByConstructor.length);
299 return result;
300 }
301
302 @Override public final boolean isOverridable() {
303 return false;
304 }
305
306 @Override public final boolean isVarArgs() {
307 return constructor.isVarArgs();
308 }
309
310 private boolean mayNeedHiddenThis() {
311 Class<?> declaringClass = constructor.getDeclaringClass();
312 if (declaringClass.getEnclosingConstructor() != null) {
313
314 return true;
315 }
316 Method enclosingMethod = declaringClass.getEnclosingMethod();
317 if (enclosingMethod != null) {
318
319 return !Modifier.isStatic(enclosingMethod.getModifiers());
320 } else {
321
322
323
324
325
326
327 return declaringClass.getEnclosingClass() != null
328 && !Modifier.isStatic(declaringClass.getModifiers());
329 }
330 }
331 }
332 }