package com.google.gson.reflect; import com.google.gson.internal..Gson.Preconditions; import com.google.gson.internal..Gson.Types; import java.lang.reflect.GenericArrayType; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.util.HashMap; import java.util.Map; public class TypeToken<T> { final Class<? super T> rawType; final Type type; final int hashCode; protected TypeToken() { this.type = getSuperclassTypeParameter(getClass()); this.rawType = .Gson.Types.getRawType(this.type); this.hashCode = this.type.hashCode(); } TypeToken(Type type) { this.type = .Gson.Types.canonicalize((Type).Gson.Preconditions.checkNotNull(type)); this.rawType = .Gson.Types.getRawType(this.type); this.hashCode = this.type.hashCode(); } static Type getSuperclassTypeParameter(Class<?> subclass) { Type superclass = subclass.getGenericSuperclass(); if ((superclass instanceof Class)) { throw new RuntimeException("Missing type parameter."); } ParameterizedType parameterized = (ParameterizedType)superclass; return .Gson.Types.canonicalize(parameterized.getActualTypeArguments()[0]); } public final Class<? super T> getRawType() { return this.rawType; } public final Type getType() { return this.type; } @Deprecated public boolean isAssignableFrom(Class<?> cls) { return isAssignableFrom(cls); } @Deprecated public boolean isAssignableFrom(Type from) { if (from == null) { return false; } if (this.type.equals(from)) { return true; } if ((this.type instanceof Class)) return this.rawType.isAssignableFrom(.Gson.Types.getRawType(from)); if ((this.type instanceof ParameterizedType)) { return isAssignableFrom(from, (ParameterizedType)this.type, new HashMap()); } if ((this.type instanceof GenericArrayType)) { return (this.rawType.isAssignableFrom(.Gson.Types.getRawType(from))) && (isAssignableFrom(from, (GenericArrayType)this.type)); } throw buildUnexpectedTypeError(this.type, new Class[] { Class.class, ParameterizedType.class, GenericArrayType.class }); } @Deprecated public boolean isAssignableFrom(TypeToken<?> token) { return isAssignableFrom(token.getType()); } private static boolean isAssignableFrom(Type from, GenericArrayType to) { Type toGenericComponentType = to.getGenericComponentType(); if ((toGenericComponentType instanceof ParameterizedType)) { Type t = from; if ((from instanceof GenericArrayType)) { t = ((GenericArrayType)from).getGenericComponentType(); } else if ((from instanceof Class)) { Class classType = (Class)from; while (classType.isArray()) { classType = classType.getComponentType(); } t = classType; } return isAssignableFrom(t, (ParameterizedType)toGenericComponentType, new HashMap()); } return true; } private static boolean isAssignableFrom(Type from, ParameterizedType to, Map<String, Type> typeVarMap) { if (from == null) { return false; } if (to.equals(from)) { return true; } Class clazz = .Gson.Types.getRawType(from); ParameterizedType ptype = null; if ((from instanceof ParameterizedType)) { ptype = (ParameterizedType)from; } if (ptype != null) { Type[] tArgs = ptype.getActualTypeArguments(); TypeVariable[] tParams = clazz.getTypeParameters(); for (int i = 0; i < tArgs.length; i++) { Type arg = tArgs[i]; TypeVariable var = tParams[i]; while ((arg instanceof TypeVariable)) { TypeVariable v = (TypeVariable)arg; arg = (Type)typeVarMap.get(v.getName()); } typeVarMap.put(var.getName(), arg); } if (typeEquals(ptype, to, typeVarMap)) { return true; } } for (Type itype : clazz.getGenericInterfaces()) { if (isAssignableFrom(itype, to, new HashMap(typeVarMap))) { return true; } } Type sType = clazz.getGenericSuperclass(); return isAssignableFrom(sType, to, new HashMap(typeVarMap)); } private static boolean typeEquals(ParameterizedType from, ParameterizedType to, Map<String, Type> typeVarMap) { if (from.getRawType().equals(to.getRawType())) { Type[] fromArgs = from.getActualTypeArguments(); Type[] toArgs = to.getActualTypeArguments(); for (int i = 0; i < fromArgs.length; i++) { if (!matches(fromArgs[i], toArgs[i], typeVarMap)) { return false; } } return true; } return false; } private static AssertionError buildUnexpectedTypeError(Type token, Class<?>[] expected) { StringBuilder exceptionMessage = new StringBuilder("Unexpected type. Expected one of: "); for (Class clazz : expected) { exceptionMessage.append(clazz.getName()).append(", "); } exceptionMessage.append("but got: ").append(token.getClass().getName()).append(", for type token: ").append(token.toString()).append('.'); return new AssertionError(exceptionMessage.toString()); } private static boolean matches(Type from, Type to, Map<String, Type> typeMap) { return (to.equals(from)) || (((from instanceof TypeVariable)) && (to.equals(typeMap.get(((TypeVariable)from).getName())))); } public final int hashCode() { return this.hashCode; } public final boolean equals(Object o) { return ((o instanceof TypeToken)) && (.Gson.Types.equals(this.type, ((TypeToken)o).type)); } public final String toString() { return .Gson.Types.typeToString(this.type); } public static TypeToken<?> get(Type type) { return new TypeToken(type); } public static <T> TypeToken<T> get(Class<T> type) { return new TypeToken(type); } }