MoreTypes.java revision 564053fc876faf8325bb0d11e009c650bfaa588b
13beaaaff52598e849659281fed35dc29a221fac4limpbizkit/**
23beaaaff52598e849659281fed35dc29a221fac4limpbizkit * Copyright (C) 2008 Google Inc.
33beaaaff52598e849659281fed35dc29a221fac4limpbizkit *
43beaaaff52598e849659281fed35dc29a221fac4limpbizkit * Licensed under the Apache License, Version 2.0 (the "License");
53beaaaff52598e849659281fed35dc29a221fac4limpbizkit * you may not use this file except in compliance with the License.
63beaaaff52598e849659281fed35dc29a221fac4limpbizkit * You may obtain a copy of the License at
73beaaaff52598e849659281fed35dc29a221fac4limpbizkit *
83beaaaff52598e849659281fed35dc29a221fac4limpbizkit * http://www.apache.org/licenses/LICENSE-2.0
93beaaaff52598e849659281fed35dc29a221fac4limpbizkit *
103beaaaff52598e849659281fed35dc29a221fac4limpbizkit * Unless required by applicable law or agreed to in writing, software
113beaaaff52598e849659281fed35dc29a221fac4limpbizkit * distributed under the License is distributed on an "AS IS" BASIS,
123beaaaff52598e849659281fed35dc29a221fac4limpbizkit * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133beaaaff52598e849659281fed35dc29a221fac4limpbizkit * See the License for the specific language governing permissions and
143beaaaff52598e849659281fed35dc29a221fac4limpbizkit * limitations under the License.
153beaaaff52598e849659281fed35dc29a221fac4limpbizkit */
163beaaaff52598e849659281fed35dc29a221fac4limpbizkit
173beaaaff52598e849659281fed35dc29a221fac4limpbizkit
183beaaaff52598e849659281fed35dc29a221fac4limpbizkitpackage com.google.inject.internal;
193beaaaff52598e849659281fed35dc29a221fac4limpbizkit
203beaaaff52598e849659281fed35dc29a221fac4limpbizkitimport com.google.common.base.Objects;
2149f67c0f62bc1748dd32e1d86616085231e974e7limpbizkitimport static com.google.common.base.Preconditions.checkArgument;
22564053fc876faf8325bb0d11e009c650bfaa588blimpbizkitimport static com.google.common.base.Preconditions.checkNotNull;
233beaaaff52598e849659281fed35dc29a221fac4limpbizkitimport com.google.common.collect.ImmutableMap;
243beaaaff52598e849659281fed35dc29a221fac4limpbizkitimport com.google.inject.TypeLiteral;
253beaaaff52598e849659281fed35dc29a221fac4limpbizkitimport com.google.inject.util.Types;
263beaaaff52598e849659281fed35dc29a221fac4limpbizkitimport java.io.Serializable;
27564053fc876faf8325bb0d11e009c650bfaa588blimpbizkitimport java.lang.reflect.Constructor;
28564053fc876faf8325bb0d11e009c650bfaa588blimpbizkitimport java.lang.reflect.Field;
293beaaaff52598e849659281fed35dc29a221fac4limpbizkitimport java.lang.reflect.GenericArrayType;
30564053fc876faf8325bb0d11e009c650bfaa588blimpbizkitimport java.lang.reflect.Member;
31564053fc876faf8325bb0d11e009c650bfaa588blimpbizkitimport java.lang.reflect.Method;
323beaaaff52598e849659281fed35dc29a221fac4limpbizkitimport java.lang.reflect.ParameterizedType;
333beaaaff52598e849659281fed35dc29a221fac4limpbizkitimport java.lang.reflect.Type;
343beaaaff52598e849659281fed35dc29a221fac4limpbizkitimport java.util.Arrays;
353beaaaff52598e849659281fed35dc29a221fac4limpbizkitimport java.util.Map;
363beaaaff52598e849659281fed35dc29a221fac4limpbizkit
373beaaaff52598e849659281fed35dc29a221fac4limpbizkit/**
383beaaaff52598e849659281fed35dc29a221fac4limpbizkit * Static methods for working with types that we aren't publishing in the
393beaaaff52598e849659281fed35dc29a221fac4limpbizkit * public {@code Types} API.
403beaaaff52598e849659281fed35dc29a221fac4limpbizkit *
413beaaaff52598e849659281fed35dc29a221fac4limpbizkit * @author jessewilson@google.com (Jesse Wilson)
423beaaaff52598e849659281fed35dc29a221fac4limpbizkit */
433beaaaff52598e849659281fed35dc29a221fac4limpbizkitpublic class MoreTypes {
443beaaaff52598e849659281fed35dc29a221fac4limpbizkit  private MoreTypes() {}
453beaaaff52598e849659281fed35dc29a221fac4limpbizkit
463beaaaff52598e849659281fed35dc29a221fac4limpbizkit  private static final Map<TypeLiteral<?>, TypeLiteral<?>> PRIMITIVE_TO_WRAPPER
473beaaaff52598e849659281fed35dc29a221fac4limpbizkit      = new ImmutableMap.Builder<TypeLiteral<?>, TypeLiteral<?>>()
483beaaaff52598e849659281fed35dc29a221fac4limpbizkit          .put(TypeLiteral.get(boolean.class), TypeLiteral.get(Boolean.class))
493beaaaff52598e849659281fed35dc29a221fac4limpbizkit          .put(TypeLiteral.get(byte.class), TypeLiteral.get(Byte.class))
503beaaaff52598e849659281fed35dc29a221fac4limpbizkit          .put(TypeLiteral.get(short.class), TypeLiteral.get(Short.class))
513beaaaff52598e849659281fed35dc29a221fac4limpbizkit          .put(TypeLiteral.get(int.class), TypeLiteral.get(Integer.class))
523beaaaff52598e849659281fed35dc29a221fac4limpbizkit          .put(TypeLiteral.get(long.class), TypeLiteral.get(Long.class))
533beaaaff52598e849659281fed35dc29a221fac4limpbizkit          .put(TypeLiteral.get(float.class), TypeLiteral.get(Float.class))
543beaaaff52598e849659281fed35dc29a221fac4limpbizkit          .put(TypeLiteral.get(double.class), TypeLiteral.get(Double.class))
553beaaaff52598e849659281fed35dc29a221fac4limpbizkit          .put(TypeLiteral.get(char.class), TypeLiteral.get(Character.class))
563beaaaff52598e849659281fed35dc29a221fac4limpbizkit          .put(TypeLiteral.get(void.class), TypeLiteral.get(Void.class))
573beaaaff52598e849659281fed35dc29a221fac4limpbizkit          .build();
583beaaaff52598e849659281fed35dc29a221fac4limpbizkit
593beaaaff52598e849659281fed35dc29a221fac4limpbizkit  /**
603beaaaff52598e849659281fed35dc29a221fac4limpbizkit   * Returns an equivalent (but not necessarily equal) type literal that is
613beaaaff52598e849659281fed35dc29a221fac4limpbizkit   * free of primitive types. Type literals of primitives will return the
623beaaaff52598e849659281fed35dc29a221fac4limpbizkit   * corresponding wrapper types.
633beaaaff52598e849659281fed35dc29a221fac4limpbizkit   */
643beaaaff52598e849659281fed35dc29a221fac4limpbizkit  public static <T> TypeLiteral<T> wrapPrimitives(TypeLiteral<T> typeLiteral) {
653beaaaff52598e849659281fed35dc29a221fac4limpbizkit    @SuppressWarnings("unchecked")
663beaaaff52598e849659281fed35dc29a221fac4limpbizkit    TypeLiteral<T> wrappedPrimitives = (TypeLiteral<T>) PRIMITIVE_TO_WRAPPER.get(typeLiteral);
673beaaaff52598e849659281fed35dc29a221fac4limpbizkit    return wrappedPrimitives != null
683beaaaff52598e849659281fed35dc29a221fac4limpbizkit        ? wrappedPrimitives
693beaaaff52598e849659281fed35dc29a221fac4limpbizkit        : typeLiteral;
703beaaaff52598e849659281fed35dc29a221fac4limpbizkit  }
713beaaaff52598e849659281fed35dc29a221fac4limpbizkit
723beaaaff52598e849659281fed35dc29a221fac4limpbizkit  /**
733beaaaff52598e849659281fed35dc29a221fac4limpbizkit   * Returns a type that is functionally equal but not necessarily equal
743beaaaff52598e849659281fed35dc29a221fac4limpbizkit   * according to {@link Object#equals(Object) Object.equals()}. The returned
753beaaaff52598e849659281fed35dc29a221fac4limpbizkit   * type is {@link Serializable}.
763beaaaff52598e849659281fed35dc29a221fac4limpbizkit   */
773beaaaff52598e849659281fed35dc29a221fac4limpbizkit  public static Type canonicalize(Type type) {
783beaaaff52598e849659281fed35dc29a221fac4limpbizkit    if (type instanceof ParameterizedTypeImpl
793beaaaff52598e849659281fed35dc29a221fac4limpbizkit        || type instanceof GenericArrayTypeImpl) {
803beaaaff52598e849659281fed35dc29a221fac4limpbizkit      return type;
813beaaaff52598e849659281fed35dc29a221fac4limpbizkit
823beaaaff52598e849659281fed35dc29a221fac4limpbizkit    } else if (type instanceof ParameterizedType) {
833beaaaff52598e849659281fed35dc29a221fac4limpbizkit      ParameterizedType p = (ParameterizedType) type;
843beaaaff52598e849659281fed35dc29a221fac4limpbizkit      return Types.newParameterizedTypeWithOwner(p.getOwnerType(),
853beaaaff52598e849659281fed35dc29a221fac4limpbizkit          p.getRawType(), p.getActualTypeArguments());
863beaaaff52598e849659281fed35dc29a221fac4limpbizkit
873beaaaff52598e849659281fed35dc29a221fac4limpbizkit    } else if (type instanceof GenericArrayType) {
883beaaaff52598e849659281fed35dc29a221fac4limpbizkit      GenericArrayType g = (GenericArrayType) type;
893beaaaff52598e849659281fed35dc29a221fac4limpbizkit      return Types.arrayOf(g.getGenericComponentType());
903beaaaff52598e849659281fed35dc29a221fac4limpbizkit
913beaaaff52598e849659281fed35dc29a221fac4limpbizkit    } else if (type instanceof Class<?> && ((Class<?>) type).isArray()) {
923beaaaff52598e849659281fed35dc29a221fac4limpbizkit      Class<?> c = (Class<?>) type;
933beaaaff52598e849659281fed35dc29a221fac4limpbizkit      return Types.arrayOf(c.getComponentType());
943beaaaff52598e849659281fed35dc29a221fac4limpbizkit
953beaaaff52598e849659281fed35dc29a221fac4limpbizkit    } else {
963beaaaff52598e849659281fed35dc29a221fac4limpbizkit      // type is either serializable as-is or unsupported
973beaaaff52598e849659281fed35dc29a221fac4limpbizkit      return type;
983beaaaff52598e849659281fed35dc29a221fac4limpbizkit    }
993beaaaff52598e849659281fed35dc29a221fac4limpbizkit  }
1003beaaaff52598e849659281fed35dc29a221fac4limpbizkit
101564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit  /**
102564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit   * Returns a type that's functionally equal but not necessarily equal
103564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit   * according to {@link Object#equals(Object) Object.equals}. The returned
104564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit   * member is {@link Serializable}.
105564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit   */
106564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit  public static Member canonicalize(Member member) {
107564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit    return member instanceof MemberImpl
108564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit        ? member
109564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit        : new MemberImpl(member);
110564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit  }
111564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit
1123beaaaff52598e849659281fed35dc29a221fac4limpbizkit  public static Class<?> getRawType(Type type) {
1133beaaaff52598e849659281fed35dc29a221fac4limpbizkit    if (type instanceof Class<?>) {
1143beaaaff52598e849659281fed35dc29a221fac4limpbizkit      // type is a normal class.
1153beaaaff52598e849659281fed35dc29a221fac4limpbizkit      return (Class<?>) type;
1163beaaaff52598e849659281fed35dc29a221fac4limpbizkit
1173beaaaff52598e849659281fed35dc29a221fac4limpbizkit    } else if (type instanceof ParameterizedType) {
1183beaaaff52598e849659281fed35dc29a221fac4limpbizkit      ParameterizedType parameterizedType = (ParameterizedType) type;
1193beaaaff52598e849659281fed35dc29a221fac4limpbizkit
1203beaaaff52598e849659281fed35dc29a221fac4limpbizkit      // I'm not exactly sure why getRawType() returns Type instead of Class.
1213beaaaff52598e849659281fed35dc29a221fac4limpbizkit      // Neal isn't either but suspects some pathological case related
1223beaaaff52598e849659281fed35dc29a221fac4limpbizkit      // to nested classes exists.
1233beaaaff52598e849659281fed35dc29a221fac4limpbizkit      Type rawType = parameterizedType.getRawType();
1243beaaaff52598e849659281fed35dc29a221fac4limpbizkit      if (!(rawType instanceof Class<?>)) {
1253beaaaff52598e849659281fed35dc29a221fac4limpbizkit        throw unexpectedType(rawType, Class.class);
1263beaaaff52598e849659281fed35dc29a221fac4limpbizkit      }
1273beaaaff52598e849659281fed35dc29a221fac4limpbizkit      return (Class<?>) rawType;
1283beaaaff52598e849659281fed35dc29a221fac4limpbizkit
1293beaaaff52598e849659281fed35dc29a221fac4limpbizkit    } else if (type instanceof GenericArrayType) {
1303beaaaff52598e849659281fed35dc29a221fac4limpbizkit      // TODO: Is this sufficient?
1313beaaaff52598e849659281fed35dc29a221fac4limpbizkit      return Object[].class;
1323beaaaff52598e849659281fed35dc29a221fac4limpbizkit
1333beaaaff52598e849659281fed35dc29a221fac4limpbizkit    } else {
1343beaaaff52598e849659281fed35dc29a221fac4limpbizkit      // type is a parameterized type.
1353beaaaff52598e849659281fed35dc29a221fac4limpbizkit      throw unexpectedType(type, ParameterizedType.class);
1363beaaaff52598e849659281fed35dc29a221fac4limpbizkit    }
1373beaaaff52598e849659281fed35dc29a221fac4limpbizkit  }
1383beaaaff52598e849659281fed35dc29a221fac4limpbizkit
1393beaaaff52598e849659281fed35dc29a221fac4limpbizkit  private static AssertionError unexpectedType(Type type, Class<?> expected) {
1403beaaaff52598e849659281fed35dc29a221fac4limpbizkit    return new AssertionError(
1413beaaaff52598e849659281fed35dc29a221fac4limpbizkit        "Unexpected type. Expected: " + expected.getName()
1423beaaaff52598e849659281fed35dc29a221fac4limpbizkit        + ", got: " + type.getClass().getName()
1433beaaaff52598e849659281fed35dc29a221fac4limpbizkit        + ", for type literal: " + type.toString() + ".");
1443beaaaff52598e849659281fed35dc29a221fac4limpbizkit  }
1453beaaaff52598e849659281fed35dc29a221fac4limpbizkit
1463beaaaff52598e849659281fed35dc29a221fac4limpbizkit  /**
1473beaaaff52598e849659281fed35dc29a221fac4limpbizkit   * Returns true if {@code a} and {@code b} are equal.
1483beaaaff52598e849659281fed35dc29a221fac4limpbizkit   */
1493beaaaff52598e849659281fed35dc29a221fac4limpbizkit  public static boolean equals(Type a, Type b) {
1503beaaaff52598e849659281fed35dc29a221fac4limpbizkit    if (a == b) {
1513beaaaff52598e849659281fed35dc29a221fac4limpbizkit      // also handles (a == null && b == null)
1523beaaaff52598e849659281fed35dc29a221fac4limpbizkit      return true;
1533beaaaff52598e849659281fed35dc29a221fac4limpbizkit
1543beaaaff52598e849659281fed35dc29a221fac4limpbizkit    } else if (a instanceof Class) {
1553beaaaff52598e849659281fed35dc29a221fac4limpbizkit      // Class already specifies equals().
1563beaaaff52598e849659281fed35dc29a221fac4limpbizkit      return a.equals(b);
1573beaaaff52598e849659281fed35dc29a221fac4limpbizkit
1583beaaaff52598e849659281fed35dc29a221fac4limpbizkit    } else if (a instanceof ParameterizedType) {
1593beaaaff52598e849659281fed35dc29a221fac4limpbizkit      if (!(b instanceof ParameterizedType)) {
1603beaaaff52598e849659281fed35dc29a221fac4limpbizkit        return false;
1613beaaaff52598e849659281fed35dc29a221fac4limpbizkit      }
1623beaaaff52598e849659281fed35dc29a221fac4limpbizkit
1633beaaaff52598e849659281fed35dc29a221fac4limpbizkit      ParameterizedType pa = (ParameterizedType) a;
1643beaaaff52598e849659281fed35dc29a221fac4limpbizkit      ParameterizedType pb = (ParameterizedType) b;
1653beaaaff52598e849659281fed35dc29a221fac4limpbizkit      return Objects.equal(pa.getOwnerType(), pb.getOwnerType())
1663beaaaff52598e849659281fed35dc29a221fac4limpbizkit          && pa.getRawType().equals(pb.getRawType())
1673beaaaff52598e849659281fed35dc29a221fac4limpbizkit          && Arrays.equals(pa.getActualTypeArguments(), pb.getActualTypeArguments());
1683beaaaff52598e849659281fed35dc29a221fac4limpbizkit
1693beaaaff52598e849659281fed35dc29a221fac4limpbizkit    } else if (a instanceof GenericArrayType) {
1703beaaaff52598e849659281fed35dc29a221fac4limpbizkit      if (!(b instanceof GenericArrayType)) {
1713beaaaff52598e849659281fed35dc29a221fac4limpbizkit        return false;
1723beaaaff52598e849659281fed35dc29a221fac4limpbizkit      }
1733beaaaff52598e849659281fed35dc29a221fac4limpbizkit
1743beaaaff52598e849659281fed35dc29a221fac4limpbizkit      GenericArrayType ga = (GenericArrayType) a;
1753beaaaff52598e849659281fed35dc29a221fac4limpbizkit      GenericArrayType gb = (GenericArrayType) b;
1763beaaaff52598e849659281fed35dc29a221fac4limpbizkit      return equals(ga.getGenericComponentType(), gb.getGenericComponentType());
1773beaaaff52598e849659281fed35dc29a221fac4limpbizkit
1783beaaaff52598e849659281fed35dc29a221fac4limpbizkit    } else {
1793beaaaff52598e849659281fed35dc29a221fac4limpbizkit      // This isn't a type we support. Could be a generic array type, wildcard
1803beaaaff52598e849659281fed35dc29a221fac4limpbizkit      // type, etc.
1813beaaaff52598e849659281fed35dc29a221fac4limpbizkit      return false;
1823beaaaff52598e849659281fed35dc29a221fac4limpbizkit    }
1833beaaaff52598e849659281fed35dc29a221fac4limpbizkit  }
1843beaaaff52598e849659281fed35dc29a221fac4limpbizkit
1853beaaaff52598e849659281fed35dc29a221fac4limpbizkit  /**
1863beaaaff52598e849659281fed35dc29a221fac4limpbizkit   * Returns the hashCode of {@code type}.
1873beaaaff52598e849659281fed35dc29a221fac4limpbizkit   */
1883beaaaff52598e849659281fed35dc29a221fac4limpbizkit  public static int hashCode(Type type) {
1893beaaaff52598e849659281fed35dc29a221fac4limpbizkit    if (type instanceof Class) {
1903beaaaff52598e849659281fed35dc29a221fac4limpbizkit      // Class specifies hashCode().
1913beaaaff52598e849659281fed35dc29a221fac4limpbizkit      return type.hashCode();
1923beaaaff52598e849659281fed35dc29a221fac4limpbizkit
1933beaaaff52598e849659281fed35dc29a221fac4limpbizkit    } else if (type instanceof ParameterizedType) {
1943beaaaff52598e849659281fed35dc29a221fac4limpbizkit      ParameterizedType p = (ParameterizedType) type;
1953beaaaff52598e849659281fed35dc29a221fac4limpbizkit      return Arrays.hashCode(p.getActualTypeArguments())
1963beaaaff52598e849659281fed35dc29a221fac4limpbizkit          ^ p.getRawType().hashCode()
1973beaaaff52598e849659281fed35dc29a221fac4limpbizkit          ^ hashCodeOrZero(p.getOwnerType());
1983beaaaff52598e849659281fed35dc29a221fac4limpbizkit
1993beaaaff52598e849659281fed35dc29a221fac4limpbizkit    } else if (type instanceof GenericArrayType) {
2003beaaaff52598e849659281fed35dc29a221fac4limpbizkit      return hashCode(((GenericArrayType) type).getGenericComponentType());
2013beaaaff52598e849659281fed35dc29a221fac4limpbizkit
2023beaaaff52598e849659281fed35dc29a221fac4limpbizkit    } else {
2033beaaaff52598e849659281fed35dc29a221fac4limpbizkit      // This isn't a type we support. Could be a generic array type, wildcard type, etc.
2043beaaaff52598e849659281fed35dc29a221fac4limpbizkit      return hashCodeOrZero(type);
2053beaaaff52598e849659281fed35dc29a221fac4limpbizkit    }
2063beaaaff52598e849659281fed35dc29a221fac4limpbizkit  }
2073beaaaff52598e849659281fed35dc29a221fac4limpbizkit
2083beaaaff52598e849659281fed35dc29a221fac4limpbizkit  private static int hashCodeOrZero(Object o) {
2093beaaaff52598e849659281fed35dc29a221fac4limpbizkit    return o != null ? o.hashCode() : 0;
2103beaaaff52598e849659281fed35dc29a221fac4limpbizkit  }
2113beaaaff52598e849659281fed35dc29a221fac4limpbizkit
2123beaaaff52598e849659281fed35dc29a221fac4limpbizkit  public static String toString(Type type) {
2133beaaaff52598e849659281fed35dc29a221fac4limpbizkit    if (type instanceof Class<?>) {
2143beaaaff52598e849659281fed35dc29a221fac4limpbizkit      return ((Class) type).getName();
2153beaaaff52598e849659281fed35dc29a221fac4limpbizkit
2163beaaaff52598e849659281fed35dc29a221fac4limpbizkit    } else if (type instanceof ParameterizedType) {
2173beaaaff52598e849659281fed35dc29a221fac4limpbizkit      ParameterizedType parameterizedType = (ParameterizedType) type;
2183beaaaff52598e849659281fed35dc29a221fac4limpbizkit      Type[] arguments = parameterizedType.getActualTypeArguments();
2193beaaaff52598e849659281fed35dc29a221fac4limpbizkit      Type ownerType = parameterizedType.getOwnerType();
2203beaaaff52598e849659281fed35dc29a221fac4limpbizkit      StringBuilder stringBuilder = new StringBuilder();
2213beaaaff52598e849659281fed35dc29a221fac4limpbizkit      if (ownerType != null) {
2223beaaaff52598e849659281fed35dc29a221fac4limpbizkit        stringBuilder.append(toString(ownerType)).append(".");
2233beaaaff52598e849659281fed35dc29a221fac4limpbizkit      }
2243beaaaff52598e849659281fed35dc29a221fac4limpbizkit      stringBuilder.append(toString(parameterizedType.getRawType()))
2253beaaaff52598e849659281fed35dc29a221fac4limpbizkit          .append("<")
2263beaaaff52598e849659281fed35dc29a221fac4limpbizkit          .append(toString(arguments[0]));
2273beaaaff52598e849659281fed35dc29a221fac4limpbizkit      for (int i = 1; i < arguments.length; i++) {
2283beaaaff52598e849659281fed35dc29a221fac4limpbizkit        stringBuilder.append(", ").append(toString(arguments[i]));
2293beaaaff52598e849659281fed35dc29a221fac4limpbizkit      }
2303beaaaff52598e849659281fed35dc29a221fac4limpbizkit      return stringBuilder.append(">").toString();
2313beaaaff52598e849659281fed35dc29a221fac4limpbizkit
2323beaaaff52598e849659281fed35dc29a221fac4limpbizkit    } else if (type instanceof GenericArrayType) {
2333beaaaff52598e849659281fed35dc29a221fac4limpbizkit      return toString(((GenericArrayType) type).getGenericComponentType()) + "[]";
2343beaaaff52598e849659281fed35dc29a221fac4limpbizkit
2353beaaaff52598e849659281fed35dc29a221fac4limpbizkit    } else {
2363beaaaff52598e849659281fed35dc29a221fac4limpbizkit      return type.toString();
2373beaaaff52598e849659281fed35dc29a221fac4limpbizkit    }
2383beaaaff52598e849659281fed35dc29a221fac4limpbizkit  }
2393beaaaff52598e849659281fed35dc29a221fac4limpbizkit
240564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit  /**
241564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit   * Returns {@code Field.class}, {@code Method.class} or {@code Constructor.class}.
242564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit   */
243564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit  public static Class<? extends Member> memberType(Member member) {
244564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit    checkNotNull(member, "member");
245564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit
246564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit    if (member instanceof MemberImpl) {
247564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit      return ((MemberImpl) member).memberType;
248564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit
249564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit    } else if (member instanceof Field) {
250564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit      return Field.class;
251564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit
252564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit    } else if (member instanceof Method) {
253564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit      return Method.class;
254564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit
255564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit    } else if (member instanceof Constructor) {
256564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit      return Constructor.class;
257564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit
258564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit    } else {
259564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit      throw new IllegalArgumentException(
260564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit          "Unsupported implementation class for Member, " + member.getClass());
261564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit    }
262564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit  }
263564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit
264564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit  public static String memberKey(Member member) {
265564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit    checkNotNull(member, "member");
266564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit
267564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit    if (member instanceof MemberImpl) {
268564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit      return ((MemberImpl) member).memberKey;
269564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit
270564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit    } else if (member instanceof Field) {
271564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit      return member.getName();
272564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit
273564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit    } else if (member instanceof Method) {
274564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit      return member.getName() + org.objectweb.asm.Type.getMethodDescriptor((Method) member);
275564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit
276564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit    } else if (member instanceof Constructor) {
277564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit      StringBuilder sb = new StringBuilder().append("<init>(");
278564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit      for (Class param : ((Constructor) member).getParameterTypes()) {
279564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit          sb.append(org.objectweb.asm.Type.getDescriptor(param));
280564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit      }
281564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit      return sb.append(")V").toString();
282564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit
283564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit    } else {
284564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit      throw new IllegalArgumentException(
285564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit          "Unsupported implementation class for Member, " + member.getClass());
286564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit    }
287564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit  }
288564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit
2893beaaaff52598e849659281fed35dc29a221fac4limpbizkit  public static class ParameterizedTypeImpl implements ParameterizedType, Serializable {
2903beaaaff52598e849659281fed35dc29a221fac4limpbizkit    private final Type ownerType;
2913beaaaff52598e849659281fed35dc29a221fac4limpbizkit    private final Type rawType;
2923beaaaff52598e849659281fed35dc29a221fac4limpbizkit    private final Type[] typeArguments;
2933beaaaff52598e849659281fed35dc29a221fac4limpbizkit
2943beaaaff52598e849659281fed35dc29a221fac4limpbizkit    public ParameterizedTypeImpl(Type ownerType, Type rawType, Type... typeArguments) {
29549f67c0f62bc1748dd32e1d86616085231e974e7limpbizkit      // require an owner type if the raw type needs it
29649f67c0f62bc1748dd32e1d86616085231e974e7limpbizkit      if (rawType instanceof Class<?>) {
29749f67c0f62bc1748dd32e1d86616085231e974e7limpbizkit        Class rawTypeAsClass = (Class) rawType;
29849f67c0f62bc1748dd32e1d86616085231e974e7limpbizkit        checkArgument(ownerType != null || rawTypeAsClass.getEnclosingClass() == null,
29949f67c0f62bc1748dd32e1d86616085231e974e7limpbizkit            "No owner type for enclosed %s", rawType);
30049f67c0f62bc1748dd32e1d86616085231e974e7limpbizkit        checkArgument(ownerType == null || rawTypeAsClass.getEnclosingClass() != null,
30149f67c0f62bc1748dd32e1d86616085231e974e7limpbizkit            "Owner type for unenclosed %s", rawType);
30249f67c0f62bc1748dd32e1d86616085231e974e7limpbizkit      }
30349f67c0f62bc1748dd32e1d86616085231e974e7limpbizkit
3043beaaaff52598e849659281fed35dc29a221fac4limpbizkit      this.ownerType = ownerType == null ? null : canonicalize(ownerType);
3053beaaaff52598e849659281fed35dc29a221fac4limpbizkit      this.rawType = canonicalize(rawType);
3063beaaaff52598e849659281fed35dc29a221fac4limpbizkit      this.typeArguments = typeArguments.clone();
3073beaaaff52598e849659281fed35dc29a221fac4limpbizkit      for (int t = 0; t < this.typeArguments.length; t++) {
30849f67c0f62bc1748dd32e1d86616085231e974e7limpbizkit        checkArgument(!(this.typeArguments[t] instanceof Class<?>)
3093beaaaff52598e849659281fed35dc29a221fac4limpbizkit            || !((Class) this.typeArguments[t]).isPrimitive(),
3103beaaaff52598e849659281fed35dc29a221fac4limpbizkit            "Parameterized types may not have primitive arguments: %s", this.typeArguments[t]);
3113beaaaff52598e849659281fed35dc29a221fac4limpbizkit        this.typeArguments[t] = canonicalize(this.typeArguments[t]);
3123beaaaff52598e849659281fed35dc29a221fac4limpbizkit      }
3133beaaaff52598e849659281fed35dc29a221fac4limpbizkit    }
3143beaaaff52598e849659281fed35dc29a221fac4limpbizkit
3153beaaaff52598e849659281fed35dc29a221fac4limpbizkit    public Type[] getActualTypeArguments() {
3163beaaaff52598e849659281fed35dc29a221fac4limpbizkit      return typeArguments.clone();
3173beaaaff52598e849659281fed35dc29a221fac4limpbizkit    }
3183beaaaff52598e849659281fed35dc29a221fac4limpbizkit
3193beaaaff52598e849659281fed35dc29a221fac4limpbizkit    public Type getRawType() {
3203beaaaff52598e849659281fed35dc29a221fac4limpbizkit      return rawType;
3213beaaaff52598e849659281fed35dc29a221fac4limpbizkit    }
3223beaaaff52598e849659281fed35dc29a221fac4limpbizkit
3233beaaaff52598e849659281fed35dc29a221fac4limpbizkit    public Type getOwnerType() {
3243beaaaff52598e849659281fed35dc29a221fac4limpbizkit      return ownerType;
3253beaaaff52598e849659281fed35dc29a221fac4limpbizkit    }
3263beaaaff52598e849659281fed35dc29a221fac4limpbizkit
3273beaaaff52598e849659281fed35dc29a221fac4limpbizkit    @Override public boolean equals(Object other) {
3283beaaaff52598e849659281fed35dc29a221fac4limpbizkit      return other instanceof ParameterizedType
3293beaaaff52598e849659281fed35dc29a221fac4limpbizkit          && MoreTypes.equals(this, (ParameterizedType) other);
3303beaaaff52598e849659281fed35dc29a221fac4limpbizkit    }
3313beaaaff52598e849659281fed35dc29a221fac4limpbizkit
3323beaaaff52598e849659281fed35dc29a221fac4limpbizkit    @Override public int hashCode() {
3333beaaaff52598e849659281fed35dc29a221fac4limpbizkit      return MoreTypes.hashCode(this);
3343beaaaff52598e849659281fed35dc29a221fac4limpbizkit    }
3353beaaaff52598e849659281fed35dc29a221fac4limpbizkit
3363beaaaff52598e849659281fed35dc29a221fac4limpbizkit    @Override public String toString() {
3373beaaaff52598e849659281fed35dc29a221fac4limpbizkit      return MoreTypes.toString(this);
3383beaaaff52598e849659281fed35dc29a221fac4limpbizkit    }
3393beaaaff52598e849659281fed35dc29a221fac4limpbizkit
3403beaaaff52598e849659281fed35dc29a221fac4limpbizkit    private static final long serialVersionUID = 0;
3413beaaaff52598e849659281fed35dc29a221fac4limpbizkit  }
3423beaaaff52598e849659281fed35dc29a221fac4limpbizkit
3433beaaaff52598e849659281fed35dc29a221fac4limpbizkit  public static class GenericArrayTypeImpl implements GenericArrayType, Serializable {
3443beaaaff52598e849659281fed35dc29a221fac4limpbizkit    private final Type componentType;
3453beaaaff52598e849659281fed35dc29a221fac4limpbizkit
3463beaaaff52598e849659281fed35dc29a221fac4limpbizkit    public GenericArrayTypeImpl(Type componentType) {
3473beaaaff52598e849659281fed35dc29a221fac4limpbizkit      this.componentType = canonicalize(componentType);
3483beaaaff52598e849659281fed35dc29a221fac4limpbizkit    }
3493beaaaff52598e849659281fed35dc29a221fac4limpbizkit
3503beaaaff52598e849659281fed35dc29a221fac4limpbizkit    public Type getGenericComponentType() {
3513beaaaff52598e849659281fed35dc29a221fac4limpbizkit      return componentType;
3523beaaaff52598e849659281fed35dc29a221fac4limpbizkit    }
3533beaaaff52598e849659281fed35dc29a221fac4limpbizkit
3543beaaaff52598e849659281fed35dc29a221fac4limpbizkit    @Override public boolean equals(Object o) {
3553beaaaff52598e849659281fed35dc29a221fac4limpbizkit      return o instanceof GenericArrayType
3563beaaaff52598e849659281fed35dc29a221fac4limpbizkit          && MoreTypes.equals(this, (GenericArrayType) o);
3573beaaaff52598e849659281fed35dc29a221fac4limpbizkit    }
3583beaaaff52598e849659281fed35dc29a221fac4limpbizkit
3593beaaaff52598e849659281fed35dc29a221fac4limpbizkit    @Override public int hashCode() {
3603beaaaff52598e849659281fed35dc29a221fac4limpbizkit      return MoreTypes.hashCode(this);
3613beaaaff52598e849659281fed35dc29a221fac4limpbizkit    }
3623beaaaff52598e849659281fed35dc29a221fac4limpbizkit
3633beaaaff52598e849659281fed35dc29a221fac4limpbizkit    @Override public String toString() {
3643beaaaff52598e849659281fed35dc29a221fac4limpbizkit      return MoreTypes.toString(this);
3653beaaaff52598e849659281fed35dc29a221fac4limpbizkit    }
3663beaaaff52598e849659281fed35dc29a221fac4limpbizkit
3673beaaaff52598e849659281fed35dc29a221fac4limpbizkit    private static final long serialVersionUID = 0;
3683beaaaff52598e849659281fed35dc29a221fac4limpbizkit  }
369564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit
370564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit  /**
371564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit   * We cannot serialize the built-in Java member classes, which prevents us from using Members in
372564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit   * our exception types. We workaround this with this serializable implementation. It includes all
373564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit   * of the API methods, plus everything we use for line numbers and messaging.
374564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit   */
375564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit  public static class MemberImpl implements Member, Serializable {
376564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit    private final Class<?> declaringClass;
377564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit    private final String name;
378564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit    private final int modifiers;
379564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit    private final boolean synthetic;
380564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit    private final Class<? extends Member> memberType;
381564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit    private final String memberKey;
382564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit
383564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit    private MemberImpl(Member member) {
384564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit      this.declaringClass = member.getDeclaringClass();
385564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit      this.name = member.getName();
386564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit      this.modifiers = member.getModifiers();
387564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit      this.synthetic = member.isSynthetic();
388564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit      this.memberType = memberType(member);
389564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit      this.memberKey = memberKey(member);
390564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit    }
391564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit
392564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit    public Class getDeclaringClass() {
393564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit      return declaringClass;
394564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit    }
395564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit
396564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit    public String getName() {
397564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit      return name;
398564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit    }
399564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit
400564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit    public int getModifiers() {
401564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit      return modifiers;
402564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit    }
403564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit
404564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit    public boolean isSynthetic() {
405564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit      return synthetic;
406564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit    }
407564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit
408564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit    @Override public String toString() {
409564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit      if (memberType == Method.class) {
410564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit        return "method " + getDeclaringClass().getName() + "." + getName() + "()";
411564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit      } else if (memberType == Field.class) {
412564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit        return "field " + getDeclaringClass().getName() + "." + getName();
413564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit      } else if (memberType == Constructor.class) {
414564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit        return "constructor " + getDeclaringClass().getName() + "()";
415564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit      } else {
416564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit        throw new AssertionError();
417564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit      }
418564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit    }
419564053fc876faf8325bb0d11e009c650bfaa588blimpbizkit  }
4203beaaaff52598e849659281fed35dc29a221fac4limpbizkit}
421