• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (C) 2006 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.inject;
18 
19 import static com.google.common.base.Preconditions.checkArgument;
20 import static com.google.common.base.Preconditions.checkNotNull;
21 import static com.google.inject.internal.MoreTypes.canonicalize;
22 
23 import com.google.common.collect.ImmutableList;
24 import com.google.inject.internal.MoreTypes;
25 import com.google.inject.util.Types;
26 
27 import java.lang.reflect.Constructor;
28 import java.lang.reflect.Field;
29 import java.lang.reflect.GenericArrayType;
30 import java.lang.reflect.Member;
31 import java.lang.reflect.Method;
32 import java.lang.reflect.ParameterizedType;
33 import java.lang.reflect.Type;
34 import java.lang.reflect.TypeVariable;
35 import java.lang.reflect.WildcardType;
36 import java.util.List;
37 
38 /**
39  * Represents a generic type {@code T}. Java doesn't yet provide a way to
40  * represent generic types, so this class does. Forces clients to create a
41  * subclass of this class which enables retrieval the type information even at
42  * runtime.
43  *
44  * <p>For example, to create a type literal for {@code List<String>}, you can
45  * create an empty anonymous inner class:
46  *
47  * <p>
48  * {@code TypeLiteral<List<String>> list = new TypeLiteral<List<String>>() {};}
49  *
50  * <p>Along with modeling generic types, this class can resolve type parameters.
51  * For example, to figure out what type {@code keySet()} returns on a {@code
52  * Map<Integer, String>}, use this code:<pre>   {@code
53  *
54  *   TypeLiteral<Map<Integer, String>> mapType
55  *       = new TypeLiteral<Map<Integer, String>>() {};
56  *   TypeLiteral<?> keySetType
57  *       = mapType.getReturnType(Map.class.getMethod("keySet"));
58  *   System.out.println(keySetType); // prints "Set<Integer>"}</pre>
59  *
60  * @author crazybob@google.com (Bob Lee)
61  * @author jessewilson@google.com (Jesse Wilson)
62  */
63 public class TypeLiteral<T> {
64 
65   final Class<? super T> rawType;
66   final Type type;
67   final int hashCode;
68 
69   /**
70    * Constructs a new type literal. Derives represented class from type
71    * parameter.
72    *
73    * <p>Clients create an empty anonymous subclass. Doing so embeds the type
74    * parameter in the anonymous class's type hierarchy so we can reconstitute it
75    * at runtime despite erasure.
76    */
77   @SuppressWarnings("unchecked")
TypeLiteral()78   protected TypeLiteral() {
79     this.type = getSuperclassTypeParameter(getClass());
80     this.rawType = (Class<? super T>) MoreTypes.getRawType(type);
81     this.hashCode = type.hashCode();
82   }
83 
84   /**
85    * Unsafe. Constructs a type literal manually.
86    */
87   @SuppressWarnings("unchecked")
TypeLiteral(Type type)88   TypeLiteral(Type type) {
89     this.type = canonicalize(checkNotNull(type, "type"));
90     this.rawType = (Class<? super T>) MoreTypes.getRawType(this.type);
91     this.hashCode = this.type.hashCode();
92   }
93 
94   /**
95    * Returns the type from super class's type parameter in {@link MoreTypes#canonicalize(Type)
96    * canonical form}.
97    */
getSuperclassTypeParameter(Class<?> subclass)98   static Type getSuperclassTypeParameter(Class<?> subclass) {
99     Type superclass = subclass.getGenericSuperclass();
100     if (superclass instanceof Class) {
101       throw new RuntimeException("Missing type parameter.");
102     }
103     ParameterizedType parameterized = (ParameterizedType) superclass;
104     return canonicalize(parameterized.getActualTypeArguments()[0]);
105   }
106 
107   /**
108    * Gets type literal from super class's type parameter.
109    */
fromSuperclassTypeParameter(Class<?> subclass)110   static TypeLiteral<?> fromSuperclassTypeParameter(Class<?> subclass) {
111     return new TypeLiteral<Object>(getSuperclassTypeParameter(subclass));
112   }
113 
114   /**
115    * Returns the raw (non-generic) type for this type.
116    *
117    * @since 2.0
118    */
getRawType()119   public final Class<? super T> getRawType() {
120     return rawType;
121   }
122 
123   /**
124    * Gets underlying {@code Type} instance.
125    */
getType()126   public final Type getType() {
127     return type;
128   }
129 
130   /**
131    * Gets the type of this type's provider.
132    */
133   @SuppressWarnings("unchecked")
providerType()134   final TypeLiteral<Provider<T>> providerType() {
135     // This cast is safe and wouldn't generate a warning if Type had a type
136     // parameter.
137     return (TypeLiteral<Provider<T>>) get(Types.providerOf(getType()));
138   }
139 
hashCode()140   @Override public final int hashCode() {
141     return this.hashCode;
142   }
143 
equals(Object o)144   @Override public final boolean equals(Object o) {
145     return o instanceof TypeLiteral<?>
146         && MoreTypes.equals(type, ((TypeLiteral) o).type);
147   }
148 
toString()149   @Override public final String toString() {
150     return MoreTypes.typeToString(type);
151   }
152 
153   /**
154    * Gets type literal for the given {@code Type} instance.
155    */
get(Type type)156   public static TypeLiteral<?> get(Type type) {
157     return new TypeLiteral<Object>(type);
158   }
159 
160   /**
161    * Gets type literal for the given {@code Class} instance.
162    */
get(Class<T> type)163   public static <T> TypeLiteral<T> get(Class<T> type) {
164     return new TypeLiteral<T>(type);
165   }
166 
167 
168   /** Returns an immutable list of the resolved types. */
resolveAll(Type[] types)169   private List<TypeLiteral<?>> resolveAll(Type[] types) {
170     TypeLiteral<?>[] result = new TypeLiteral<?>[types.length];
171     for (int t = 0; t < types.length; t++) {
172       result[t] = resolve(types[t]);
173     }
174     return ImmutableList.copyOf(result);
175   }
176 
177   /**
178    * Resolves known type parameters in {@code toResolve} and returns the result.
179    */
resolve(Type toResolve)180   TypeLiteral<?> resolve(Type toResolve) {
181     return TypeLiteral.get(resolveType(toResolve));
182   }
183 
resolveType(Type toResolve)184   Type resolveType(Type toResolve) {
185     // this implementation is made a little more complicated in an attempt to avoid object-creation
186     while (true) {
187       if (toResolve instanceof TypeVariable) {
188         TypeVariable original = (TypeVariable) toResolve;
189         toResolve = MoreTypes.resolveTypeVariable(type, rawType, original);
190         if (toResolve == original) {
191           return toResolve;
192         }
193 
194       } else if (toResolve instanceof GenericArrayType) {
195         GenericArrayType original = (GenericArrayType) toResolve;
196         Type componentType = original.getGenericComponentType();
197         Type newComponentType = resolveType(componentType);
198         return componentType == newComponentType
199             ? original
200             : Types.arrayOf(newComponentType);
201 
202       } else if (toResolve instanceof ParameterizedType) {
203         ParameterizedType original = (ParameterizedType) toResolve;
204         Type ownerType = original.getOwnerType();
205         Type newOwnerType = resolveType(ownerType);
206         boolean changed = newOwnerType != ownerType;
207 
208         Type[] args = original.getActualTypeArguments();
209         for (int t = 0, length = args.length; t < length; t++) {
210           Type resolvedTypeArgument = resolveType(args[t]);
211           if (resolvedTypeArgument != args[t]) {
212             if (!changed) {
213               args = args.clone();
214               changed = true;
215             }
216             args[t] = resolvedTypeArgument;
217           }
218         }
219 
220         return changed
221             ? Types.newParameterizedTypeWithOwner(newOwnerType, original.getRawType(), args)
222             : original;
223 
224       } else if (toResolve instanceof WildcardType) {
225         WildcardType original = (WildcardType) toResolve;
226         Type[] originalLowerBound = original.getLowerBounds();
227         Type[] originalUpperBound = original.getUpperBounds();
228 
229         if (originalLowerBound.length == 1) {
230           Type lowerBound = resolveType(originalLowerBound[0]);
231           if (lowerBound != originalLowerBound[0]) {
232             return Types.supertypeOf(lowerBound);
233           }
234         } else if (originalUpperBound.length == 1) {
235           Type upperBound = resolveType(originalUpperBound[0]);
236           if (upperBound != originalUpperBound[0]) {
237             return Types.subtypeOf(upperBound);
238           }
239         }
240         return original;
241 
242       } else {
243         return toResolve;
244       }
245     }
246   }
247 
248   /**
249    * Returns the generic form of {@code supertype}. For example, if this is {@code
250    * ArrayList<String>}, this returns {@code Iterable<String>} given the input {@code
251    * Iterable.class}.
252    *
253    * @param supertype a superclass of, or interface implemented by, this.
254    * @since 2.0
255    */
getSupertype(Class<?> supertype)256   public TypeLiteral<?> getSupertype(Class<?> supertype) {
257     checkArgument(supertype.isAssignableFrom(rawType),
258         "%s is not a supertype of %s", supertype, this.type);
259     return resolve(MoreTypes.getGenericSupertype(type, rawType, supertype));
260   }
261 
262   /**
263    * Returns the resolved generic type of {@code field}.
264    *
265    * @param field a field defined by this or any superclass.
266    * @since 2.0
267    */
getFieldType(Field field)268   public TypeLiteral<?> getFieldType(Field field) {
269     checkArgument(field.getDeclaringClass().isAssignableFrom(rawType),
270         "%s is not defined by a supertype of %s", field, type);
271     return resolve(field.getGenericType());
272   }
273 
274   /**
275    * Returns the resolved generic parameter types of {@code methodOrConstructor}.
276    *
277    * @param methodOrConstructor a method or constructor defined by this or any supertype.
278    * @since 2.0
279    */
getParameterTypes(Member methodOrConstructor)280   public List<TypeLiteral<?>> getParameterTypes(Member methodOrConstructor) {
281     Type[] genericParameterTypes;
282 
283     if (methodOrConstructor instanceof Method) {
284       Method method = (Method) methodOrConstructor;
285       checkArgument(method.getDeclaringClass().isAssignableFrom(rawType),
286           "%s is not defined by a supertype of %s", method, type);
287       genericParameterTypes = method.getGenericParameterTypes();
288 
289     } else if (methodOrConstructor instanceof Constructor) {
290       Constructor<?> constructor = (Constructor<?>) methodOrConstructor;
291       checkArgument(constructor.getDeclaringClass().isAssignableFrom(rawType),
292           "%s does not construct a supertype of %s", constructor, type);
293       genericParameterTypes = constructor.getGenericParameterTypes();
294 
295     } else {
296       throw new IllegalArgumentException("Not a method or a constructor: " + methodOrConstructor);
297     }
298 
299     return resolveAll(genericParameterTypes);
300   }
301 
302   /**
303    * Returns the resolved generic exception types thrown by {@code constructor}.
304    *
305    * @param methodOrConstructor a method or constructor defined by this or any supertype.
306    * @since 2.0
307    */
getExceptionTypes(Member methodOrConstructor)308   public List<TypeLiteral<?>> getExceptionTypes(Member methodOrConstructor) {
309     Type[] genericExceptionTypes;
310 
311     if (methodOrConstructor instanceof Method) {
312       Method method = (Method) methodOrConstructor;
313       checkArgument(method.getDeclaringClass().isAssignableFrom(rawType),
314           "%s is not defined by a supertype of %s", method, type);
315       genericExceptionTypes = method.getGenericExceptionTypes();
316 
317     } else if (methodOrConstructor instanceof Constructor) {
318       Constructor<?> constructor = (Constructor<?>) methodOrConstructor;
319       checkArgument(constructor.getDeclaringClass().isAssignableFrom(rawType),
320           "%s does not construct a supertype of %s", constructor, type);
321       genericExceptionTypes = constructor.getGenericExceptionTypes();
322 
323     } else {
324       throw new IllegalArgumentException("Not a method or a constructor: " + methodOrConstructor);
325     }
326 
327     return resolveAll(genericExceptionTypes);
328   }
329 
330   /**
331    * Returns the resolved generic return type of {@code method}.
332    *
333    * @param method a method defined by this or any supertype.
334    * @since 2.0
335    */
getReturnType(Method method)336   public TypeLiteral<?> getReturnType(Method method) {
337     checkArgument(method.getDeclaringClass().isAssignableFrom(rawType),
338         "%s is not defined by a supertype of %s", method, type);
339     return resolve(method.getGenericReturnType());
340   }
341 }
342