185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho/**
2103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius * Copyright (C) 2008 Google Inc.
385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho *
485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho * Licensed under the Apache License, Version 2.0 (the "License");
5103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius * you may not use this file except in compliance with the License.
685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho * You may obtain a copy of the License at
785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho *
885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho * http://www.apache.org/licenses/LICENSE-2.0
985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho *
1085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho * Unless required by applicable law or agreed to in writing, software
1185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho * distributed under the License is distributed on an "AS IS" BASIS,
1285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho * See the License for the specific language governing permissions and
1485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho * limitations under the License.
1585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho */
1685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
17103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
18103e9ffba2cba345d0078eb8b8db33249f81840aCraig Corneliuspackage com.google.inject.internal;
19103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
2085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Hoimport static com.google.common.base.Preconditions.checkArgument;
2185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Hoimport static com.google.common.base.Preconditions.checkNotNull;
2285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
23103e9ffba2cba345d0078eb8b8db33249f81840aCraig Corneliusimport com.google.common.base.Objects;
24103e9ffba2cba345d0078eb8b8db33249f81840aCraig Corneliusimport com.google.common.collect.ImmutableMap;
25103e9ffba2cba345d0078eb8b8db33249f81840aCraig Corneliusimport com.google.inject.ConfigurationException;
2685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Hoimport com.google.inject.Key;
27103e9ffba2cba345d0078eb8b8db33249f81840aCraig Corneliusimport com.google.inject.TypeLiteral;
28b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoimport com.google.inject.util.Types;
2985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
3085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Hoimport java.io.Serializable;
3185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Hoimport java.lang.reflect.Array;
3285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Hoimport java.lang.reflect.GenericArrayType;
3385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Hoimport java.lang.reflect.GenericDeclaration;
3485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Hoimport java.lang.reflect.ParameterizedType;
3585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Hoimport java.lang.reflect.Type;
3685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Hoimport java.lang.reflect.TypeVariable;
3785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Hoimport java.lang.reflect.WildcardType;
3885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Hoimport java.util.Arrays;
3985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Hoimport java.util.Map;
4085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Hoimport java.util.NoSuchElementException;
4185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
4285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho/**
4385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho * Static methods for working with types that we aren't publishing in the
4485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho * public {@code Types} API.
4585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho *
4685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho * @author jessewilson@google.com (Jesse Wilson)
4785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho */
4885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Hopublic class MoreTypes {
4985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
50103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius  public static final Type[] EMPTY_TYPE_ARRAY = new Type[] {};
5185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
5285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho  private MoreTypes() {}
5385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
5485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho  private static final Map<TypeLiteral<?>, TypeLiteral<?>> PRIMITIVE_TO_WRAPPER
5585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      = new ImmutableMap.Builder<TypeLiteral<?>, TypeLiteral<?>>()
5685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho          .put(TypeLiteral.get(boolean.class), TypeLiteral.get(Boolean.class))
5785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho          .put(TypeLiteral.get(byte.class), TypeLiteral.get(Byte.class))
5885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho          .put(TypeLiteral.get(short.class), TypeLiteral.get(Short.class))
5985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho          .put(TypeLiteral.get(int.class), TypeLiteral.get(Integer.class))
6085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho          .put(TypeLiteral.get(long.class), TypeLiteral.get(Long.class))
6185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho          .put(TypeLiteral.get(float.class), TypeLiteral.get(Float.class))
6285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho          .put(TypeLiteral.get(double.class), TypeLiteral.get(Double.class))
6385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho          .put(TypeLiteral.get(char.class), TypeLiteral.get(Character.class))
6485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho          .put(TypeLiteral.get(void.class), TypeLiteral.get(Void.class))
6585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho          .build();
6650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
67103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius  /**
6885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho   * Returns a key that doesn't hold any references to parent classes.
6927f654740f2a26ad62a5c155af9199af9e69b889claireho   * This is necessary for anonymous keys, so ensure we don't hold a ref
7085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho   * to the containing module (or class) forever.
7185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho   */
7285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho  public static <T> Key<T> canonicalizeKey(Key<T> key) {
7385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    // If we know this isn't a subclass, return as-is.
7485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    // Otherwise, recreate the key to avoid the subclass
7585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    if (key.getClass() == Key.class) {
7685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      return key;
7785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    } else if (key.getAnnotation() != null) {
78103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius      return Key.get(key.getTypeLiteral(), key.getAnnotation());
7927f654740f2a26ad62a5c155af9199af9e69b889claireho    } else if (key.getAnnotationType() != null) {
8085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      return Key.get(key.getTypeLiteral(), key.getAnnotationType());
8150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    } else {
8250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho      return Key.get(key.getTypeLiteral());
8385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
84103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius  }
85103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
86103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius  /**
87103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius   * Returns an type that's appropriate for use in a key.
88103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius   *
8985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho   * <p>If the raw type of {@code typeLiteral} is a {@code javax.inject.Provider}, this returns a
9085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho   * {@code com.google.inject.Provider} with the same type parameters.
9185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho   *
9285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho   * <p>If the type is a primitive, the corresponding wrapper type will be returned.
9385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho   *
9485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho   * @throws ConfigurationException if {@code type} contains a type variable
9585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho   */
9685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho  public static <T> TypeLiteral<T> canonicalizeForKey(TypeLiteral<T> typeLiteral) {
9785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    Type type = typeLiteral.getType();
9885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    if (!isFullySpecified(type)) {
9985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      Errors errors = new Errors().keyNotFullySpecified(typeLiteral);
10085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      throw new ConfigurationException(errors.getMessages());
10185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
10285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
10385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    if (typeLiteral.getRawType() == javax.inject.Provider.class) {
10485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      ParameterizedType parameterizedType = (ParameterizedType) type;
10585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
10685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      // the following casts are generally unsafe, but com.google.inject.Provider extends
107103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius      // javax.inject.Provider and is covariant
108103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius      @SuppressWarnings("unchecked")
109103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius      TypeLiteral<T> guiceProviderType = (TypeLiteral<T>) TypeLiteral.get(
11085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho          Types.providerOf(parameterizedType.getActualTypeArguments()[0]));
11185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      return guiceProviderType;
11285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
11385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
11485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    @SuppressWarnings("unchecked")
11585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    TypeLiteral<T> wrappedPrimitives = (TypeLiteral<T>) PRIMITIVE_TO_WRAPPER.get(typeLiteral);
11685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    if (wrappedPrimitives != null) {
11785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      return wrappedPrimitives;
118103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    }
11985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
12085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    // If we know this isn't a subclass, return as-is.
12185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    if (typeLiteral.getClass() == TypeLiteral.class) {
12285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      return typeLiteral;
12385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
12485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
12585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    // recreate the TypeLiteral to avoid anonymous TypeLiterals from holding refs to their
12685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    // surrounding classes.
12785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    @SuppressWarnings("unchecked")
12885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    TypeLiteral<T> recreated = (TypeLiteral<T>) TypeLiteral.get(typeLiteral.getType());
12985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    return recreated;
13085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho  }
13185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
13285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho  /**
13385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho   * Returns true if {@code type} is free from type variables.
13485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho   */
13585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho  private static boolean isFullySpecified(Type type) {
13685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    if (type instanceof Class) {
13785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      return true;
13885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
13985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    } else if (type instanceof CompositeType) {
14085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      return ((CompositeType) type).isFullySpecified();
14185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
14285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    } else if (type instanceof TypeVariable){
14385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      return false;
14485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
14585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    } else {
14685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      return ((CompositeType) canonicalize(type)).isFullySpecified();
14785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
14885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho  }
149103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
150103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius  /**
151103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius   * Returns a type that is functionally equal but not necessarily equal
15285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho   * according to {@link Object#equals(Object) Object.equals()}. The returned
15385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho   * type is {@link Serializable}.
154103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius   */
15585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho  public static Type canonicalize(Type type) {
15685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    if (type instanceof Class) {
15785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      Class<?> c = (Class<?>) type;
15885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      return c.isArray() ? new GenericArrayTypeImpl(canonicalize(c.getComponentType())) : c;
15985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
16085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    } else if (type instanceof CompositeType) {
16185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      return type;
16285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
16385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    } else if (type instanceof ParameterizedType) {
16485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      ParameterizedType p = (ParameterizedType) type;
16585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      return new ParameterizedTypeImpl(p.getOwnerType(),
16685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho          p.getRawType(), p.getActualTypeArguments());
16785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
16885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    } else if (type instanceof GenericArrayType) {
16985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      GenericArrayType g = (GenericArrayType) type;
17085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      return new GenericArrayTypeImpl(g.getGenericComponentType());
17185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
17285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    } else if (type instanceof WildcardType) {
17385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      WildcardType w = (WildcardType) type;
17485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      return new WildcardTypeImpl(w.getUpperBounds(), w.getLowerBounds());
175103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
176103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    } else {
177103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius      // type is either serializable as-is or unsupported
178103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius      return type;
179103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    }
180103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius  }
181103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
182103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius  public static Class<?> getRawType(Type type) {
183103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    if (type instanceof Class<?>) {
184103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius      // type is a normal class.
185103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius      return (Class<?>) type;
186103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
187103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    } else if (type instanceof ParameterizedType) {
188103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius      ParameterizedType parameterizedType = (ParameterizedType) type;
189103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
190103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius      // I'm not exactly sure why getRawType() returns Type instead of Class.
191103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius      // Neal isn't either but suspects some pathological case related
192103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius      // to nested classes exists.
193103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius      Type rawType = parameterizedType.getRawType();
19485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      checkArgument(rawType instanceof Class,
19585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho          "Expected a Class, but <%s> is of type %s", type, type.getClass().getName());
19685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      return (Class<?>) rawType;
19785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
19885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    } else if (type instanceof GenericArrayType) {
19985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      Type componentType = ((GenericArrayType)type).getGenericComponentType();
20085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      return Array.newInstance(getRawType(componentType), 0).getClass();
201103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
20285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    } else if (type instanceof TypeVariable) {
203103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius      // we could use the variable's bounds, but that'll won't work if there are multiple.
204103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius      // having a raw type that's more general than necessary is okay
205103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius      return Object.class;
20685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
20785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    } else {
20885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      throw new IllegalArgumentException("Expected a Class, ParameterizedType, or "
20985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho          + "GenericArrayType, but <" + type + "> is of type " + type.getClass().getName());
21085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
21150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho  }
21285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
21385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho  /**
21485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho   * Returns true if {@code a} and {@code b} are equal.
21585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho   */
21685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho  public static boolean equals(Type a, Type b) {
21785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    if (a == b) {
21885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      // also handles (a == null && b == null)
21985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      return true;
22085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
22185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    } else if (a instanceof Class) {
22285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      // Class already specifies equals().
22385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      return a.equals(b);
22485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
22585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    } else if (a instanceof ParameterizedType) {
22685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      if (!(b instanceof ParameterizedType)) {
22785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        return false;
22885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      }
22985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
23085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      // TODO: save a .clone() call
23185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      ParameterizedType pa = (ParameterizedType) a;
23250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho      ParameterizedType pb = (ParameterizedType) b;
23385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      return Objects.equal(pa.getOwnerType(), pb.getOwnerType())
23485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho          && pa.getRawType().equals(pb.getRawType())
235103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius          && Arrays.equals(pa.getActualTypeArguments(), pb.getActualTypeArguments());
236103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
23785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    } else if (a instanceof GenericArrayType) {
23885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      if (!(b instanceof GenericArrayType)) {
23985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        return false;
24085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      }
24185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
24285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      GenericArrayType ga = (GenericArrayType) a;
24385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      GenericArrayType gb = (GenericArrayType) b;
24485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      return equals(ga.getGenericComponentType(), gb.getGenericComponentType());
24585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
24685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    } else if (a instanceof WildcardType) {
24785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      if (!(b instanceof WildcardType)) {
24885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        return false;
24985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      }
25085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
25185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      WildcardType wa = (WildcardType) a;
25285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      WildcardType wb = (WildcardType) b;
25385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      return Arrays.equals(wa.getUpperBounds(), wb.getUpperBounds())
25485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho          && Arrays.equals(wa.getLowerBounds(), wb.getLowerBounds());
25585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
25685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    } else if (a instanceof TypeVariable) {
25785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      if (!(b instanceof TypeVariable)) {
25885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        return false;
25985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      }
26085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      TypeVariable<?> va = (TypeVariable) a;
26185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      TypeVariable<?> vb = (TypeVariable) b;
26285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      return va.getGenericDeclaration().equals(vb.getGenericDeclaration())
26385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho          && va.getName().equals(vb.getName());
26485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
26585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    } else {
26685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      // This isn't a type we support. Could be a generic array type, wildcard type, etc.
26785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      return false;
26885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
26985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho  }
27085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
27185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho  private static int hashCodeOrZero(Object o) {
27285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    return o != null ? o.hashCode() : 0;
27385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho  }
27485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
27585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho  public static String typeToString(Type type) {
27685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    return type instanceof Class ? ((Class) type).getName() : type.toString();
27785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho  }
27885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
27985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho  /**
28050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho   * Returns the generic supertype for {@code type}. For example, given a class {@code IntegerSet},
28150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho   * the result for when supertype is {@code Set.class} is {@code Set<Integer>} and the result
28250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho   * when the supertype is {@code Collection.class} is {@code Collection<Integer>}.
28350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho   */
28485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho  public static Type getGenericSupertype(Type type, Class<?> rawType, Class<?> toResolve) {
28585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    if (toResolve == rawType) {
28685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      return type;
28785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
28885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
28985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    // we skip searching through interfaces if unknown is an interface
29085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    if (toResolve.isInterface()) {
29185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      Class[] interfaces = rawType.getInterfaces();
29285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      for (int i = 0, length = interfaces.length; i < length; i++) {
29385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        if (interfaces[i] == toResolve) {
29485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho          return rawType.getGenericInterfaces()[i];
29585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        } else if (toResolve.isAssignableFrom(interfaces[i])) {
29685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho          return getGenericSupertype(rawType.getGenericInterfaces()[i], interfaces[i], toResolve);
29785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        }
29885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      }
29985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
30085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
30185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    // check our supertypes
30285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    if (!rawType.isInterface()) {
30385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      while (rawType != Object.class) {
30485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        Class<?> rawSupertype = rawType.getSuperclass();
30585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        if (rawSupertype == toResolve) {
30685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho          return rawType.getGenericSuperclass();
30785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        } else if (toResolve.isAssignableFrom(rawSupertype)) {
30885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho          return getGenericSupertype(rawType.getGenericSuperclass(), rawSupertype, toResolve);
30985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        }
31085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        rawType = rawSupertype;
31185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      }
31285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
31385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
31485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    // we can't resolve this further
31585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    return toResolve;
31685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho  }
31785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
31885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho  public static Type resolveTypeVariable(Type type, Class<?> rawType, TypeVariable unknown) {
31985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    Class<?> declaredByRaw = declaringClassOf(unknown);
32085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
32185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    // we can't reduce this further
32285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    if (declaredByRaw == null) {
32385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      return unknown;
32485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
32585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
32685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    Type declaredBy = getGenericSupertype(type, rawType, declaredByRaw);
32785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    if (declaredBy instanceof ParameterizedType) {
32885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      int index = indexOf(declaredByRaw.getTypeParameters(), unknown);
32985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      return ((ParameterizedType) declaredBy).getActualTypeArguments()[index];
33085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
33185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
33285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    return unknown;
33385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho  }
33485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
33585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho  private static int indexOf(Object[] array, Object toFind) {
33685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    for (int i = 0; i < array.length; i++) {
33785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      if (toFind.equals(array[i])) {
33885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        return i;
33985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      }
34085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
34185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    throw new NoSuchElementException();
34285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho  }
34385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
34485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho  /**
34585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho   * Returns the declaring class of {@code typeVariable}, or {@code null} if it was not declared by
34685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho   * a class.
34785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho   */
34885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho  private static Class<?> declaringClassOf(TypeVariable typeVariable) {
34985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration();
35085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    return genericDeclaration instanceof Class
35185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        ? (Class<?>) genericDeclaration
35285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        : null;
35385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho  }
35485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
35585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho  public static class ParameterizedTypeImpl
35685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      implements ParameterizedType, Serializable, CompositeType {
35785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    private final Type ownerType;
35885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    private final Type rawType;
35985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    private final Type[] typeArguments;
36085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
36185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    public ParameterizedTypeImpl(Type ownerType, Type rawType, Type... typeArguments) {
36285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      // require an owner type if the raw type needs it
36385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      ensureOwnerType(ownerType, rawType);
36485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
36585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      this.ownerType = ownerType == null ? null : canonicalize(ownerType);
36685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      this.rawType = canonicalize(rawType);
36785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      this.typeArguments = typeArguments.clone();
36885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      for (int t = 0; t < this.typeArguments.length; t++) {
36985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        checkNotNull(this.typeArguments[t], "type parameter");
37085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        checkNotPrimitive(this.typeArguments[t], "type parameters");
37185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        this.typeArguments[t] = canonicalize(this.typeArguments[t]);
37285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      }
37385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
37485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
37585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    public Type[] getActualTypeArguments() {
376103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius      return typeArguments.clone();
377103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    }
378103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
379103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    public Type getRawType() {
380103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius      return rawType;
381103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    }
38285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
38385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    public Type getOwnerType() {
38450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho      return ownerType;
38550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    }
38650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
38750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    public boolean isFullySpecified() {
38850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho      if (ownerType != null && !MoreTypes.isFullySpecified(ownerType)) {
38950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        return false;
39050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho      }
39185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
39285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      if (!MoreTypes.isFullySpecified(rawType)) {
39385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        return false;
39485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      }
39585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
39685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      for (Type type : typeArguments) {
39785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        if (!MoreTypes.isFullySpecified(type)) {
39885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho          return false;
39985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        }
40085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      }
40185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
40285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      return true;
40385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
40485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
40585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    @Override public boolean equals(Object other) {
40685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      return other instanceof ParameterizedType
40785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho          && MoreTypes.equals(this, (ParameterizedType) other);
40885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
40985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
41085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    @Override public int hashCode() {
41185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      return Arrays.hashCode(typeArguments)
41285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho          ^ rawType.hashCode()
41385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho          ^ hashCodeOrZero(ownerType);
41485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
41585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
41685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    @Override public String toString() {
41785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      StringBuilder stringBuilder = new StringBuilder(30 * (typeArguments.length + 1));
41885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      stringBuilder.append(typeToString(rawType));
41985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
42085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      if (typeArguments.length == 0) {
42185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        return stringBuilder.toString();
42285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      }
42385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
42485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      stringBuilder.append("<").append(typeToString(typeArguments[0]));
42585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      for (int i = 1; i < typeArguments.length; i++) {
42685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        stringBuilder.append(", ").append(typeToString(typeArguments[i]));
42785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      }
42885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      return stringBuilder.append(">").toString();
42985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
430103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
431103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    private static void ensureOwnerType(Type ownerType, Type rawType) {
432103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius      if (rawType instanceof Class<?>) {
433103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        Class rawTypeAsClass = (Class) rawType;
434103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        checkArgument(ownerType != null || rawTypeAsClass.getEnclosingClass() == null,
435103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            "No owner type for enclosed %s", rawType);
436103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        checkArgument(ownerType == null || rawTypeAsClass.getEnclosingClass() != null,
437103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            "Owner type for unenclosed %s", rawType);
438103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius      }
439103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    }
44085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
44185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    private static final long serialVersionUID = 0;
44285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho  }
44385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
44485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho  public static class GenericArrayTypeImpl
44585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      implements GenericArrayType, Serializable, CompositeType {
44685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    private final Type componentType;
44785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
44885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    public GenericArrayTypeImpl(Type componentType) {
44985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      this.componentType = canonicalize(componentType);
45085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
45185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
45285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    public Type getGenericComponentType() {
45385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      return componentType;
45485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
45585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
45685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    public boolean isFullySpecified() {
45785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      return MoreTypes.isFullySpecified(componentType);
45885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
45985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
46085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    @Override public boolean equals(Object o) {
46185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      return o instanceof GenericArrayType
46285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho          && MoreTypes.equals(this, (GenericArrayType) o);
46385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
46485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
46585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    @Override public int hashCode() {
46685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      return componentType.hashCode();
46785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
46885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
46985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    @Override public String toString() {
47085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      return typeToString(componentType) + "[]";
47185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
47285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
47385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    private static final long serialVersionUID = 0;
47485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho  }
47585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
47685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho  /**
47785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho   * The WildcardType interface supports multiple upper bounds and multiple
47885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho   * lower bounds. We only support what the Java 6 language needs - at most one
47985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho   * bound. If a lower bound is set, the upper bound must be Object.class.
48050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho   */
48127f654740f2a26ad62a5c155af9199af9e69b889claireho  public static class WildcardTypeImpl implements WildcardType, Serializable, CompositeType {
48227f654740f2a26ad62a5c155af9199af9e69b889claireho    private final Type upperBound;
48327f654740f2a26ad62a5c155af9199af9e69b889claireho    private final Type lowerBound;
48427f654740f2a26ad62a5c155af9199af9e69b889claireho
48527f654740f2a26ad62a5c155af9199af9e69b889claireho    public WildcardTypeImpl(Type[] upperBounds, Type[] lowerBounds) {
48627f654740f2a26ad62a5c155af9199af9e69b889claireho      checkArgument(lowerBounds.length <= 1, "Must have at most one lower bound.");
48727f654740f2a26ad62a5c155af9199af9e69b889claireho      checkArgument(upperBounds.length == 1, "Must have exactly one upper bound.");
48850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
48950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho      if (lowerBounds.length == 1) {
490103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        checkNotNull(lowerBounds[0], "lowerBound");
491b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        checkNotPrimitive(lowerBounds[0], "wildcard bounds");
492b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        checkArgument(upperBounds[0] == Object.class, "bounded both ways");
49327f654740f2a26ad62a5c155af9199af9e69b889claireho        this.lowerBound = canonicalize(lowerBounds[0]);
49427f654740f2a26ad62a5c155af9199af9e69b889claireho        this.upperBound = Object.class;
49527f654740f2a26ad62a5c155af9199af9e69b889claireho
496103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius      } else {
49750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        checkNotNull(upperBounds[0], "upperBound");
49850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        checkNotPrimitive(upperBounds[0], "wildcard bounds");
499103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        this.lowerBound = null;
50050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        this.upperBound = canonicalize(upperBounds[0]);
50127f654740f2a26ad62a5c155af9199af9e69b889claireho      }
50250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    }
50350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
50450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    public Type[] getUpperBounds() {
50550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho      return new Type[] { upperBound };
506103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    }
50750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
508103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    public Type[] getLowerBounds() {
50927f654740f2a26ad62a5c155af9199af9e69b889claireho      return lowerBound != null ? new Type[] { lowerBound } : EMPTY_TYPE_ARRAY;
51050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    }
51127f654740f2a26ad62a5c155af9199af9e69b889claireho
51250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    public boolean isFullySpecified() {
51350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho      return MoreTypes.isFullySpecified(upperBound)
51427f654740f2a26ad62a5c155af9199af9e69b889claireho          && (lowerBound == null || MoreTypes.isFullySpecified(lowerBound));
515103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    }
51650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
51727f654740f2a26ad62a5c155af9199af9e69b889claireho    @Override public boolean equals(Object other) {
51827f654740f2a26ad62a5c155af9199af9e69b889claireho      return other instanceof WildcardType
51927f654740f2a26ad62a5c155af9199af9e69b889claireho          && MoreTypes.equals(this, (WildcardType) other);
52027f654740f2a26ad62a5c155af9199af9e69b889claireho    }
52127f654740f2a26ad62a5c155af9199af9e69b889claireho
52227f654740f2a26ad62a5c155af9199af9e69b889claireho    @Override public int hashCode() {
52327f654740f2a26ad62a5c155af9199af9e69b889claireho      // this equals Arrays.hashCode(getLowerBounds()) ^ Arrays.hashCode(getUpperBounds());
52450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho      return (lowerBound != null ? 31 + lowerBound.hashCode() : 1)
52585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho          ^ (31 + upperBound.hashCode());
52685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
52785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
52885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    @Override public String toString() {
52985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      if (lowerBound != null) {
53027f654740f2a26ad62a5c155af9199af9e69b889claireho        return "? super " + typeToString(lowerBound);
53185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      } else if (upperBound == Object.class) {
53285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        return "?";
53385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      } else {
53485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        return "? extends " + typeToString(upperBound);
53585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho      }
53685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
53785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
53827f654740f2a26ad62a5c155af9199af9e69b889claireho    private static final long serialVersionUID = 0;
53927f654740f2a26ad62a5c155af9199af9e69b889claireho  }
540103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
54185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho  private static void checkNotPrimitive(Type type, String use) {
54285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    checkArgument(!(type instanceof Class<?>) || !((Class) type).isPrimitive(),
54385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        "Primitive types are not allowed in %s: %s", use, type);
54485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho  }
54585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
54685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho  /** A type formed from other types, such as arrays, parameterized types or wildcard types */
54785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho  private interface CompositeType {
54850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    /** Returns true if there are no type variables in this type. */
54950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    boolean isFullySpecified();
55050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho  }
55150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho}
55285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho