• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (C) 2008 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 
18 package com.google.inject.internal;
19 
20 import static com.google.common.base.Preconditions.checkArgument;
21 import static com.google.common.base.Preconditions.checkNotNull;
22 
23 import com.google.common.base.Objects;
24 import com.google.common.collect.ImmutableMap;
25 import com.google.inject.ConfigurationException;
26 import com.google.inject.Key;
27 import com.google.inject.TypeLiteral;
28 import com.google.inject.util.Types;
29 
30 import java.io.Serializable;
31 import java.lang.reflect.Array;
32 import java.lang.reflect.GenericArrayType;
33 import java.lang.reflect.GenericDeclaration;
34 import java.lang.reflect.ParameterizedType;
35 import java.lang.reflect.Type;
36 import java.lang.reflect.TypeVariable;
37 import java.lang.reflect.WildcardType;
38 import java.util.Arrays;
39 import java.util.Map;
40 import java.util.NoSuchElementException;
41 
42 /**
43  * Static methods for working with types that we aren't publishing in the
44  * public {@code Types} API.
45  *
46  * @author jessewilson@google.com (Jesse Wilson)
47  */
48 public class MoreTypes {
49 
50   public static final Type[] EMPTY_TYPE_ARRAY = new Type[] {};
51 
MoreTypes()52   private MoreTypes() {}
53 
54   private static final Map<TypeLiteral<?>, TypeLiteral<?>> PRIMITIVE_TO_WRAPPER
55       = new ImmutableMap.Builder<TypeLiteral<?>, TypeLiteral<?>>()
56           .put(TypeLiteral.get(boolean.class), TypeLiteral.get(Boolean.class))
57           .put(TypeLiteral.get(byte.class), TypeLiteral.get(Byte.class))
58           .put(TypeLiteral.get(short.class), TypeLiteral.get(Short.class))
59           .put(TypeLiteral.get(int.class), TypeLiteral.get(Integer.class))
60           .put(TypeLiteral.get(long.class), TypeLiteral.get(Long.class))
61           .put(TypeLiteral.get(float.class), TypeLiteral.get(Float.class))
62           .put(TypeLiteral.get(double.class), TypeLiteral.get(Double.class))
63           .put(TypeLiteral.get(char.class), TypeLiteral.get(Character.class))
64           .put(TypeLiteral.get(void.class), TypeLiteral.get(Void.class))
65           .build();
66 
67   /**
68    * Returns a key that doesn't hold any references to parent classes.
69    * This is necessary for anonymous keys, so ensure we don't hold a ref
70    * to the containing module (or class) forever.
71    */
canonicalizeKey(Key<T> key)72   public static <T> Key<T> canonicalizeKey(Key<T> key) {
73     // If we know this isn't a subclass, return as-is.
74     // Otherwise, recreate the key to avoid the subclass
75     if (key.getClass() == Key.class) {
76       return key;
77     } else if (key.getAnnotation() != null) {
78       return Key.get(key.getTypeLiteral(), key.getAnnotation());
79     } else if (key.getAnnotationType() != null) {
80       return Key.get(key.getTypeLiteral(), key.getAnnotationType());
81     } else {
82       return Key.get(key.getTypeLiteral());
83     }
84   }
85 
86   /**
87    * Returns an type that's appropriate for use in a key.
88    *
89    * <p>If the raw type of {@code typeLiteral} is a {@code javax.inject.Provider}, this returns a
90    * {@code com.google.inject.Provider} with the same type parameters.
91    *
92    * <p>If the type is a primitive, the corresponding wrapper type will be returned.
93    *
94    * @throws ConfigurationException if {@code type} contains a type variable
95    */
canonicalizeForKey(TypeLiteral<T> typeLiteral)96   public static <T> TypeLiteral<T> canonicalizeForKey(TypeLiteral<T> typeLiteral) {
97     Type type = typeLiteral.getType();
98     if (!isFullySpecified(type)) {
99       Errors errors = new Errors().keyNotFullySpecified(typeLiteral);
100       throw new ConfigurationException(errors.getMessages());
101     }
102 
103     if (typeLiteral.getRawType() == javax.inject.Provider.class) {
104       ParameterizedType parameterizedType = (ParameterizedType) type;
105 
106       // the following casts are generally unsafe, but com.google.inject.Provider extends
107       // javax.inject.Provider and is covariant
108       @SuppressWarnings("unchecked")
109       TypeLiteral<T> guiceProviderType = (TypeLiteral<T>) TypeLiteral.get(
110           Types.providerOf(parameterizedType.getActualTypeArguments()[0]));
111       return guiceProviderType;
112     }
113 
114     @SuppressWarnings("unchecked")
115     TypeLiteral<T> wrappedPrimitives = (TypeLiteral<T>) PRIMITIVE_TO_WRAPPER.get(typeLiteral);
116     if (wrappedPrimitives != null) {
117       return wrappedPrimitives;
118     }
119 
120     // If we know this isn't a subclass, return as-is.
121     if (typeLiteral.getClass() == TypeLiteral.class) {
122       return typeLiteral;
123     }
124 
125     // recreate the TypeLiteral to avoid anonymous TypeLiterals from holding refs to their
126     // surrounding classes.
127     @SuppressWarnings("unchecked")
128     TypeLiteral<T> recreated = (TypeLiteral<T>) TypeLiteral.get(typeLiteral.getType());
129     return recreated;
130   }
131 
132   /**
133    * Returns true if {@code type} is free from type variables.
134    */
isFullySpecified(Type type)135   private static boolean isFullySpecified(Type type) {
136     if (type instanceof Class) {
137       return true;
138 
139     } else if (type instanceof CompositeType) {
140       return ((CompositeType) type).isFullySpecified();
141 
142     } else if (type instanceof TypeVariable){
143       return false;
144 
145     } else {
146       return ((CompositeType) canonicalize(type)).isFullySpecified();
147     }
148   }
149 
150   /**
151    * Returns a type that is functionally equal but not necessarily equal
152    * according to {@link Object#equals(Object) Object.equals()}. The returned
153    * type is {@link Serializable}.
154    */
canonicalize(Type type)155   public static Type canonicalize(Type type) {
156     if (type instanceof Class) {
157       Class<?> c = (Class<?>) type;
158       return c.isArray() ? new GenericArrayTypeImpl(canonicalize(c.getComponentType())) : c;
159 
160     } else if (type instanceof CompositeType) {
161       return type;
162 
163     } else if (type instanceof ParameterizedType) {
164       ParameterizedType p = (ParameterizedType) type;
165       return new ParameterizedTypeImpl(p.getOwnerType(),
166           p.getRawType(), p.getActualTypeArguments());
167 
168     } else if (type instanceof GenericArrayType) {
169       GenericArrayType g = (GenericArrayType) type;
170       return new GenericArrayTypeImpl(g.getGenericComponentType());
171 
172     } else if (type instanceof WildcardType) {
173       WildcardType w = (WildcardType) type;
174       return new WildcardTypeImpl(w.getUpperBounds(), w.getLowerBounds());
175 
176     } else {
177       // type is either serializable as-is or unsupported
178       return type;
179     }
180   }
181 
getRawType(Type type)182   public static Class<?> getRawType(Type type) {
183     if (type instanceof Class<?>) {
184       // type is a normal class.
185       return (Class<?>) type;
186 
187     } else if (type instanceof ParameterizedType) {
188       ParameterizedType parameterizedType = (ParameterizedType) type;
189 
190       // I'm not exactly sure why getRawType() returns Type instead of Class.
191       // Neal isn't either but suspects some pathological case related
192       // to nested classes exists.
193       Type rawType = parameterizedType.getRawType();
194       checkArgument(rawType instanceof Class,
195           "Expected a Class, but <%s> is of type %s", type, type.getClass().getName());
196       return (Class<?>) rawType;
197 
198     } else if (type instanceof GenericArrayType) {
199       Type componentType = ((GenericArrayType)type).getGenericComponentType();
200       return Array.newInstance(getRawType(componentType), 0).getClass();
201 
202     } else if (type instanceof TypeVariable) {
203       // we could use the variable's bounds, but that'll won't work if there are multiple.
204       // having a raw type that's more general than necessary is okay
205       return Object.class;
206 
207     } else {
208       throw new IllegalArgumentException("Expected a Class, ParameterizedType, or "
209           + "GenericArrayType, but <" + type + "> is of type " + type.getClass().getName());
210     }
211   }
212 
213   /**
214    * Returns true if {@code a} and {@code b} are equal.
215    */
equals(Type a, Type b)216   public static boolean equals(Type a, Type b) {
217     if (a == b) {
218       // also handles (a == null && b == null)
219       return true;
220 
221     } else if (a instanceof Class) {
222       // Class already specifies equals().
223       return a.equals(b);
224 
225     } else if (a instanceof ParameterizedType) {
226       if (!(b instanceof ParameterizedType)) {
227         return false;
228       }
229 
230       // TODO: save a .clone() call
231       ParameterizedType pa = (ParameterizedType) a;
232       ParameterizedType pb = (ParameterizedType) b;
233       return Objects.equal(pa.getOwnerType(), pb.getOwnerType())
234           && pa.getRawType().equals(pb.getRawType())
235           && Arrays.equals(pa.getActualTypeArguments(), pb.getActualTypeArguments());
236 
237     } else if (a instanceof GenericArrayType) {
238       if (!(b instanceof GenericArrayType)) {
239         return false;
240       }
241 
242       GenericArrayType ga = (GenericArrayType) a;
243       GenericArrayType gb = (GenericArrayType) b;
244       return equals(ga.getGenericComponentType(), gb.getGenericComponentType());
245 
246     } else if (a instanceof WildcardType) {
247       if (!(b instanceof WildcardType)) {
248         return false;
249       }
250 
251       WildcardType wa = (WildcardType) a;
252       WildcardType wb = (WildcardType) b;
253       return Arrays.equals(wa.getUpperBounds(), wb.getUpperBounds())
254           && Arrays.equals(wa.getLowerBounds(), wb.getLowerBounds());
255 
256     } else if (a instanceof TypeVariable) {
257       if (!(b instanceof TypeVariable)) {
258         return false;
259       }
260       TypeVariable<?> va = (TypeVariable) a;
261       TypeVariable<?> vb = (TypeVariable) b;
262       return va.getGenericDeclaration().equals(vb.getGenericDeclaration())
263           && va.getName().equals(vb.getName());
264 
265     } else {
266       // This isn't a type we support. Could be a generic array type, wildcard type, etc.
267       return false;
268     }
269   }
270 
hashCodeOrZero(Object o)271   private static int hashCodeOrZero(Object o) {
272     return o != null ? o.hashCode() : 0;
273   }
274 
typeToString(Type type)275   public static String typeToString(Type type) {
276     return type instanceof Class ? ((Class) type).getName() : type.toString();
277   }
278 
279   /**
280    * Returns the generic supertype for {@code type}. For example, given a class {@code IntegerSet},
281    * the result for when supertype is {@code Set.class} is {@code Set<Integer>} and the result
282    * when the supertype is {@code Collection.class} is {@code Collection<Integer>}.
283    */
getGenericSupertype(Type type, Class<?> rawType, Class<?> toResolve)284   public static Type getGenericSupertype(Type type, Class<?> rawType, Class<?> toResolve) {
285     if (toResolve == rawType) {
286       return type;
287     }
288 
289     // we skip searching through interfaces if unknown is an interface
290     if (toResolve.isInterface()) {
291       Class[] interfaces = rawType.getInterfaces();
292       for (int i = 0, length = interfaces.length; i < length; i++) {
293         if (interfaces[i] == toResolve) {
294           return rawType.getGenericInterfaces()[i];
295         } else if (toResolve.isAssignableFrom(interfaces[i])) {
296           return getGenericSupertype(rawType.getGenericInterfaces()[i], interfaces[i], toResolve);
297         }
298       }
299     }
300 
301     // check our supertypes
302     if (!rawType.isInterface()) {
303       while (rawType != Object.class) {
304         Class<?> rawSupertype = rawType.getSuperclass();
305         if (rawSupertype == toResolve) {
306           return rawType.getGenericSuperclass();
307         } else if (toResolve.isAssignableFrom(rawSupertype)) {
308           return getGenericSupertype(rawType.getGenericSuperclass(), rawSupertype, toResolve);
309         }
310         rawType = rawSupertype;
311       }
312     }
313 
314     // we can't resolve this further
315     return toResolve;
316   }
317 
resolveTypeVariable(Type type, Class<?> rawType, TypeVariable unknown)318   public static Type resolveTypeVariable(Type type, Class<?> rawType, TypeVariable unknown) {
319     Class<?> declaredByRaw = declaringClassOf(unknown);
320 
321     // we can't reduce this further
322     if (declaredByRaw == null) {
323       return unknown;
324     }
325 
326     Type declaredBy = getGenericSupertype(type, rawType, declaredByRaw);
327     if (declaredBy instanceof ParameterizedType) {
328       int index = indexOf(declaredByRaw.getTypeParameters(), unknown);
329       return ((ParameterizedType) declaredBy).getActualTypeArguments()[index];
330     }
331 
332     return unknown;
333   }
334 
indexOf(Object[] array, Object toFind)335   private static int indexOf(Object[] array, Object toFind) {
336     for (int i = 0; i < array.length; i++) {
337       if (toFind.equals(array[i])) {
338         return i;
339       }
340     }
341     throw new NoSuchElementException();
342   }
343 
344   /**
345    * Returns the declaring class of {@code typeVariable}, or {@code null} if it was not declared by
346    * a class.
347    */
declaringClassOf(TypeVariable typeVariable)348   private static Class<?> declaringClassOf(TypeVariable typeVariable) {
349     GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration();
350     return genericDeclaration instanceof Class
351         ? (Class<?>) genericDeclaration
352         : null;
353   }
354 
355   public static class ParameterizedTypeImpl
356       implements ParameterizedType, Serializable, CompositeType {
357     private final Type ownerType;
358     private final Type rawType;
359     private final Type[] typeArguments;
360 
ParameterizedTypeImpl(Type ownerType, Type rawType, Type... typeArguments)361     public ParameterizedTypeImpl(Type ownerType, Type rawType, Type... typeArguments) {
362       // require an owner type if the raw type needs it
363       ensureOwnerType(ownerType, rawType);
364 
365       this.ownerType = ownerType == null ? null : canonicalize(ownerType);
366       this.rawType = canonicalize(rawType);
367       this.typeArguments = typeArguments.clone();
368       for (int t = 0; t < this.typeArguments.length; t++) {
369         checkNotNull(this.typeArguments[t], "type parameter");
370         checkNotPrimitive(this.typeArguments[t], "type parameters");
371         this.typeArguments[t] = canonicalize(this.typeArguments[t]);
372       }
373     }
374 
getActualTypeArguments()375     public Type[] getActualTypeArguments() {
376       return typeArguments.clone();
377     }
378 
getRawType()379     public Type getRawType() {
380       return rawType;
381     }
382 
getOwnerType()383     public Type getOwnerType() {
384       return ownerType;
385     }
386 
isFullySpecified()387     public boolean isFullySpecified() {
388       if (ownerType != null && !MoreTypes.isFullySpecified(ownerType)) {
389         return false;
390       }
391 
392       if (!MoreTypes.isFullySpecified(rawType)) {
393         return false;
394       }
395 
396       for (Type type : typeArguments) {
397         if (!MoreTypes.isFullySpecified(type)) {
398           return false;
399         }
400       }
401 
402       return true;
403     }
404 
equals(Object other)405     @Override public boolean equals(Object other) {
406       return other instanceof ParameterizedType
407           && MoreTypes.equals(this, (ParameterizedType) other);
408     }
409 
hashCode()410     @Override public int hashCode() {
411       return Arrays.hashCode(typeArguments)
412           ^ rawType.hashCode()
413           ^ hashCodeOrZero(ownerType);
414     }
415 
toString()416     @Override public String toString() {
417       StringBuilder stringBuilder = new StringBuilder(30 * (typeArguments.length + 1));
418       stringBuilder.append(typeToString(rawType));
419 
420       if (typeArguments.length == 0) {
421         return stringBuilder.toString();
422       }
423 
424       stringBuilder.append("<").append(typeToString(typeArguments[0]));
425       for (int i = 1; i < typeArguments.length; i++) {
426         stringBuilder.append(", ").append(typeToString(typeArguments[i]));
427       }
428       return stringBuilder.append(">").toString();
429     }
430 
ensureOwnerType(Type ownerType, Type rawType)431     private static void ensureOwnerType(Type ownerType, Type rawType) {
432       if (rawType instanceof Class<?>) {
433         Class rawTypeAsClass = (Class) rawType;
434         checkArgument(ownerType != null || rawTypeAsClass.getEnclosingClass() == null,
435             "No owner type for enclosed %s", rawType);
436         checkArgument(ownerType == null || rawTypeAsClass.getEnclosingClass() != null,
437             "Owner type for unenclosed %s", rawType);
438       }
439     }
440 
441     private static final long serialVersionUID = 0;
442   }
443 
444   public static class GenericArrayTypeImpl
445       implements GenericArrayType, Serializable, CompositeType {
446     private final Type componentType;
447 
GenericArrayTypeImpl(Type componentType)448     public GenericArrayTypeImpl(Type componentType) {
449       this.componentType = canonicalize(componentType);
450     }
451 
getGenericComponentType()452     public Type getGenericComponentType() {
453       return componentType;
454     }
455 
isFullySpecified()456     public boolean isFullySpecified() {
457       return MoreTypes.isFullySpecified(componentType);
458     }
459 
equals(Object o)460     @Override public boolean equals(Object o) {
461       return o instanceof GenericArrayType
462           && MoreTypes.equals(this, (GenericArrayType) o);
463     }
464 
hashCode()465     @Override public int hashCode() {
466       return componentType.hashCode();
467     }
468 
toString()469     @Override public String toString() {
470       return typeToString(componentType) + "[]";
471     }
472 
473     private static final long serialVersionUID = 0;
474   }
475 
476   /**
477    * The WildcardType interface supports multiple upper bounds and multiple
478    * lower bounds. We only support what the Java 6 language needs - at most one
479    * bound. If a lower bound is set, the upper bound must be Object.class.
480    */
481   public static class WildcardTypeImpl implements WildcardType, Serializable, CompositeType {
482     private final Type upperBound;
483     private final Type lowerBound;
484 
WildcardTypeImpl(Type[] upperBounds, Type[] lowerBounds)485     public WildcardTypeImpl(Type[] upperBounds, Type[] lowerBounds) {
486       checkArgument(lowerBounds.length <= 1, "Must have at most one lower bound.");
487       checkArgument(upperBounds.length == 1, "Must have exactly one upper bound.");
488 
489       if (lowerBounds.length == 1) {
490         checkNotNull(lowerBounds[0], "lowerBound");
491         checkNotPrimitive(lowerBounds[0], "wildcard bounds");
492         checkArgument(upperBounds[0] == Object.class, "bounded both ways");
493         this.lowerBound = canonicalize(lowerBounds[0]);
494         this.upperBound = Object.class;
495 
496       } else {
497         checkNotNull(upperBounds[0], "upperBound");
498         checkNotPrimitive(upperBounds[0], "wildcard bounds");
499         this.lowerBound = null;
500         this.upperBound = canonicalize(upperBounds[0]);
501       }
502     }
503 
getUpperBounds()504     public Type[] getUpperBounds() {
505       return new Type[] { upperBound };
506     }
507 
getLowerBounds()508     public Type[] getLowerBounds() {
509       return lowerBound != null ? new Type[] { lowerBound } : EMPTY_TYPE_ARRAY;
510     }
511 
isFullySpecified()512     public boolean isFullySpecified() {
513       return MoreTypes.isFullySpecified(upperBound)
514           && (lowerBound == null || MoreTypes.isFullySpecified(lowerBound));
515     }
516 
equals(Object other)517     @Override public boolean equals(Object other) {
518       return other instanceof WildcardType
519           && MoreTypes.equals(this, (WildcardType) other);
520     }
521 
hashCode()522     @Override public int hashCode() {
523       // this equals Arrays.hashCode(getLowerBounds()) ^ Arrays.hashCode(getUpperBounds());
524       return (lowerBound != null ? 31 + lowerBound.hashCode() : 1)
525           ^ (31 + upperBound.hashCode());
526     }
527 
toString()528     @Override public String toString() {
529       if (lowerBound != null) {
530         return "? super " + typeToString(lowerBound);
531       } else if (upperBound == Object.class) {
532         return "?";
533       } else {
534         return "? extends " + typeToString(upperBound);
535       }
536     }
537 
538     private static final long serialVersionUID = 0;
539   }
540 
checkNotPrimitive(Type type, String use)541   private static void checkNotPrimitive(Type type, String use) {
542     checkArgument(!(type instanceof Class<?>) || !((Class) type).isPrimitive(),
543         "Primitive types are not allowed in %s: %s", use, type);
544   }
545 
546   /** A type formed from other types, such as arrays, parameterized types or wildcard types */
547   private interface CompositeType {
548     /** Returns true if there are no type variables in this type. */
isFullySpecified()549     boolean isFullySpecified();
550   }
551 }
552