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
18package com.google.inject.internal;
19
20import static com.google.common.base.Preconditions.checkArgument;
21import static com.google.common.base.Preconditions.checkNotNull;
22
23import com.google.common.base.Objects;
24import com.google.common.collect.ImmutableMap;
25import com.google.inject.ConfigurationException;
26import com.google.inject.Key;
27import com.google.inject.TypeLiteral;
28import com.google.inject.util.Types;
29
30import java.io.Serializable;
31import java.lang.reflect.Array;
32import java.lang.reflect.GenericArrayType;
33import java.lang.reflect.GenericDeclaration;
34import java.lang.reflect.ParameterizedType;
35import java.lang.reflect.Type;
36import java.lang.reflect.TypeVariable;
37import java.lang.reflect.WildcardType;
38import java.util.Arrays;
39import java.util.Map;
40import 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 */
48public class MoreTypes {
49
50  public static final Type[] EMPTY_TYPE_ARRAY = new Type[] {};
51
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   */
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   */
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   */
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   */
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
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   */
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
271  private static int hashCodeOrZero(Object o) {
272    return o != null ? o.hashCode() : 0;
273  }
274
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   */
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
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
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   */
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
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
375    public Type[] getActualTypeArguments() {
376      return typeArguments.clone();
377    }
378
379    public Type getRawType() {
380      return rawType;
381    }
382
383    public Type getOwnerType() {
384      return ownerType;
385    }
386
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
405    @Override public boolean equals(Object other) {
406      return other instanceof ParameterizedType
407          && MoreTypes.equals(this, (ParameterizedType) other);
408    }
409
410    @Override public int hashCode() {
411      return Arrays.hashCode(typeArguments)
412          ^ rawType.hashCode()
413          ^ hashCodeOrZero(ownerType);
414    }
415
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
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
448    public GenericArrayTypeImpl(Type componentType) {
449      this.componentType = canonicalize(componentType);
450    }
451
452    public Type getGenericComponentType() {
453      return componentType;
454    }
455
456    public boolean isFullySpecified() {
457      return MoreTypes.isFullySpecified(componentType);
458    }
459
460    @Override public boolean equals(Object o) {
461      return o instanceof GenericArrayType
462          && MoreTypes.equals(this, (GenericArrayType) o);
463    }
464
465    @Override public int hashCode() {
466      return componentType.hashCode();
467    }
468
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
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
504    public Type[] getUpperBounds() {
505      return new Type[] { upperBound };
506    }
507
508    public Type[] getLowerBounds() {
509      return lowerBound != null ? new Type[] { lowerBound } : EMPTY_TYPE_ARRAY;
510    }
511
512    public boolean isFullySpecified() {
513      return MoreTypes.isFullySpecified(upperBound)
514          && (lowerBound == null || MoreTypes.isFullySpecified(lowerBound));
515    }
516
517    @Override public boolean equals(Object other) {
518      return other instanceof WildcardType
519          && MoreTypes.equals(this, (WildcardType) other);
520    }
521
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
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
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. */
549    boolean isFullySpecified();
550  }
551}
552