| /** | 
|  * Copyright (C) 2008 Google Inc. | 
|  * | 
|  * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  * you may not use this file except in compliance with the License. | 
|  * You may obtain a copy of the License at | 
|  * | 
|  * http://www.apache.org/licenses/LICENSE-2.0 | 
|  * | 
|  * Unless required by applicable law or agreed to in writing, software | 
|  * distributed under the License is distributed on an "AS IS" BASIS, | 
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  * See the License for the specific language governing permissions and | 
|  * limitations under the License. | 
|  */ | 
|   | 
| package cn.emay.sdk.util.json.gson.internal; | 
|   | 
| import static cn.emay.sdk.util.json.gson.internal.$Gson$Preconditions.checkArgument; | 
| import static cn.emay.sdk.util.json.gson.internal.$Gson$Preconditions.checkNotNull; | 
|   | 
| import java.io.Serializable; | 
| import java.lang.reflect.Array; | 
| import java.lang.reflect.GenericArrayType; | 
| import java.lang.reflect.GenericDeclaration; | 
| import java.lang.reflect.Modifier; | 
| import java.lang.reflect.ParameterizedType; | 
| import java.lang.reflect.Type; | 
| import java.lang.reflect.TypeVariable; | 
| import java.lang.reflect.WildcardType; | 
| import java.util.Arrays; | 
| import java.util.Collection; | 
| import java.util.Map; | 
| import java.util.NoSuchElementException; | 
| import java.util.Properties; | 
|   | 
| /** | 
|  * Static methods for working with types. | 
|  * | 
|  * @author Bob Lee | 
|  * @author Jesse Wilson | 
|  */ | 
| public final class $Gson$Types { | 
|     static final Type[] EMPTY_TYPE_ARRAY = new Type[] {}; | 
|   | 
|     private $Gson$Types() { | 
|         throw new UnsupportedOperationException(); | 
|     } | 
|   | 
|     /** | 
|      * Returns a new parameterized type, applying {@code typeArguments} to | 
|      * {@code rawType} and enclosed by {@code ownerType}. | 
|      * | 
|      * @return a {@link java.io.Serializable serializable} parameterized type. | 
|      */ | 
|     public static ParameterizedType newParameterizedTypeWithOwner(Type ownerType, Type rawType, Type... typeArguments) { | 
|         return new ParameterizedTypeImpl(ownerType, rawType, typeArguments); | 
|     } | 
|   | 
|     /** | 
|      * Returns an array type whose elements are all instances of | 
|      * {@code componentType}. | 
|      * | 
|      * @return a {@link java.io.Serializable serializable} generic array type. | 
|      */ | 
|     public static GenericArrayType arrayOf(Type componentType) { | 
|         return new GenericArrayTypeImpl(componentType); | 
|     } | 
|   | 
|     /** | 
|      * Returns a type that represents an unknown type that extends {@code bound}. | 
|      * For example, if {@code bound} is {@code CharSequence.class}, this returns | 
|      * {@code ? extends CharSequence}. If {@code bound} is {@code Object.class}, | 
|      * this returns {@code ?}, which is shorthand for {@code ? extends Object}. | 
|      */ | 
|     public static WildcardType subtypeOf(Type bound) { | 
|         return new WildcardTypeImpl(new Type[] { bound }, EMPTY_TYPE_ARRAY); | 
|     } | 
|   | 
|     /** | 
|      * Returns a type that represents an unknown supertype of {@code bound}. For | 
|      * example, if {@code bound} is {@code String.class}, this returns {@code ? | 
|      * super String}. | 
|      */ | 
|     public static WildcardType supertypeOf(Type bound) { | 
|         return new WildcardTypeImpl(new Type[] { Object.class }, new Type[] { bound }); | 
|     } | 
|   | 
|     /** | 
|      * Returns a type that is functionally equal but not necessarily equal according | 
|      * to {@link Object#equals(Object) Object.equals()}. The returned type is | 
|      * {@link java.io.Serializable}. | 
|      */ | 
|     public static Type canonicalize(Type type) { | 
|         if (type instanceof Class) { | 
|             Class<?> c = (Class<?>) type; | 
|             return c.isArray() ? new GenericArrayTypeImpl(canonicalize(c.getComponentType())) : c; | 
|   | 
|         } else if (type instanceof ParameterizedType) { | 
|             ParameterizedType p = (ParameterizedType) type; | 
|             return new ParameterizedTypeImpl(p.getOwnerType(), p.getRawType(), p.getActualTypeArguments()); | 
|   | 
|         } else if (type instanceof GenericArrayType) { | 
|             GenericArrayType g = (GenericArrayType) type; | 
|             return new GenericArrayTypeImpl(g.getGenericComponentType()); | 
|   | 
|         } else if (type instanceof WildcardType) { | 
|             WildcardType w = (WildcardType) type; | 
|             return new WildcardTypeImpl(w.getUpperBounds(), w.getLowerBounds()); | 
|   | 
|         } else { | 
|             // type is either serializable as-is or unsupported | 
|             return type; | 
|         } | 
|     } | 
|   | 
|     public static Class<?> getRawType(Type type) { | 
|         if (type instanceof Class<?>) { | 
|             // type is a normal class. | 
|             return (Class<?>) type; | 
|   | 
|         } else if (type instanceof ParameterizedType) { | 
|             ParameterizedType parameterizedType = (ParameterizedType) type; | 
|   | 
|             // I'm not exactly sure why getRawType() returns Type instead of Class. | 
|             // Neal isn't either but suspects some pathological case related | 
|             // to nested classes exists. | 
|             Type rawType = parameterizedType.getRawType(); | 
|             checkArgument(rawType instanceof Class); | 
|             return (Class<?>) rawType; | 
|   | 
|         } else if (type instanceof GenericArrayType) { | 
|             Type componentType = ((GenericArrayType) type).getGenericComponentType(); | 
|             return Array.newInstance(getRawType(componentType), 0).getClass(); | 
|   | 
|         } else if (type instanceof TypeVariable) { | 
|             // we could use the variable's bounds, but that won't work if there are | 
|             // multiple. | 
|             // having a raw type that's more general than necessary is okay | 
|             return Object.class; | 
|   | 
|         } else if (type instanceof WildcardType) { | 
|             return getRawType(((WildcardType) type).getUpperBounds()[0]); | 
|   | 
|         } else { | 
|             String className = type == null ? "null" : type.getClass().getName(); | 
|             throw new IllegalArgumentException("Expected a Class, ParameterizedType, or " + "GenericArrayType, but <" + type + "> is of type " + className); | 
|         } | 
|     } | 
|   | 
|     static boolean equal(Object a, Object b) { | 
|         return a == b || (a != null && a.equals(b)); | 
|     } | 
|   | 
|     /** | 
|      * Returns true if {@code a} and {@code b} are equal. | 
|      */ | 
|     public static boolean equals(Type a, Type b) { | 
|         if (a == b) { | 
|             // also handles (a == null && b == null) | 
|             return true; | 
|   | 
|         } else if (a instanceof Class) { | 
|             // Class already specifies equals(). | 
|             return a.equals(b); | 
|   | 
|         } else if (a instanceof ParameterizedType) { | 
|             if (!(b instanceof ParameterizedType)) { | 
|                 return false; | 
|             } | 
|   | 
|             // TODO: save a .clone() call | 
|             ParameterizedType pa = (ParameterizedType) a; | 
|             ParameterizedType pb = (ParameterizedType) b; | 
|             return equal(pa.getOwnerType(), pb.getOwnerType()) && pa.getRawType().equals(pb.getRawType()) && Arrays.equals(pa.getActualTypeArguments(), pb.getActualTypeArguments()); | 
|   | 
|         } else if (a instanceof GenericArrayType) { | 
|             if (!(b instanceof GenericArrayType)) { | 
|                 return false; | 
|             } | 
|   | 
|             GenericArrayType ga = (GenericArrayType) a; | 
|             GenericArrayType gb = (GenericArrayType) b; | 
|             return equals(ga.getGenericComponentType(), gb.getGenericComponentType()); | 
|   | 
|         } else if (a instanceof WildcardType) { | 
|             if (!(b instanceof WildcardType)) { | 
|                 return false; | 
|             } | 
|   | 
|             WildcardType wa = (WildcardType) a; | 
|             WildcardType wb = (WildcardType) b; | 
|             return Arrays.equals(wa.getUpperBounds(), wb.getUpperBounds()) && Arrays.equals(wa.getLowerBounds(), wb.getLowerBounds()); | 
|   | 
|         } else if (a instanceof TypeVariable) { | 
|             if (!(b instanceof TypeVariable)) { | 
|                 return false; | 
|             } | 
|             TypeVariable<?> va = (TypeVariable<?>) a; | 
|             TypeVariable<?> vb = (TypeVariable<?>) b; | 
|             return va.getGenericDeclaration() == vb.getGenericDeclaration() && va.getName().equals(vb.getName()); | 
|   | 
|         } else { | 
|             // This isn't a type we support. Could be a generic array type, wildcard type, | 
|             // etc. | 
|             return false; | 
|         } | 
|     } | 
|   | 
|     static int hashCodeOrZero(Object o) { | 
|         return o != null ? o.hashCode() : 0; | 
|     } | 
|   | 
|     public static String typeToString(Type type) { | 
|         return type instanceof Class ? ((Class<?>) type).getName() : type.toString(); | 
|     } | 
|   | 
|     /** | 
|      * Returns the generic supertype for {@code supertype}. For example, given a | 
|      * class {@code | 
|      * IntegerSet}, the result for when supertype is {@code Set.class} is | 
|      * {@code Set<Integer>} and the result when the supertype is | 
|      * {@code Collection.class} is {@code Collection<Integer>}. | 
|      */ | 
|     static Type getGenericSupertype(Type context, Class<?> rawType, Class<?> toResolve) { | 
|         if (toResolve == rawType) { | 
|             return context; | 
|         } | 
|   | 
|         // we skip searching through interfaces if unknown is an interface | 
|         if (toResolve.isInterface()) { | 
|             Class<?>[] interfaces = rawType.getInterfaces(); | 
|             for (int i = 0, length = interfaces.length; i < length; i++) { | 
|                 if (interfaces[i] == toResolve) { | 
|                     return rawType.getGenericInterfaces()[i]; | 
|                 } else if (toResolve.isAssignableFrom(interfaces[i])) { | 
|                     return getGenericSupertype(rawType.getGenericInterfaces()[i], interfaces[i], toResolve); | 
|                 } | 
|             } | 
|         } | 
|   | 
|         // check our supertypes | 
|         if (!rawType.isInterface()) { | 
|             while (rawType != Object.class) { | 
|                 Class<?> rawSupertype = rawType.getSuperclass(); | 
|                 if (rawSupertype == toResolve) { | 
|                     return rawType.getGenericSuperclass(); | 
|                 } else if (toResolve.isAssignableFrom(rawSupertype)) { | 
|                     return getGenericSupertype(rawType.getGenericSuperclass(), rawSupertype, toResolve); | 
|                 } | 
|                 rawType = rawSupertype; | 
|             } | 
|         } | 
|   | 
|         // we can't resolve this further | 
|         return toResolve; | 
|     } | 
|   | 
|     /** | 
|      * Returns the generic form of {@code supertype}. For example, if this is {@code | 
|      * ArrayList<String>}, this returns {@code Iterable<String>} given the input | 
|      * {@code | 
|      * Iterable.class}. | 
|      * | 
|      * @param supertype | 
|      *            a superclass of, or interface implemented by, this. | 
|      */ | 
|     static Type getSupertype(Type context, Class<?> contextRawType, Class<?> supertype) { | 
|         checkArgument(supertype.isAssignableFrom(contextRawType)); | 
|         return resolve(context, contextRawType, $Gson$Types.getGenericSupertype(context, contextRawType, supertype)); | 
|     } | 
|   | 
|     /** | 
|      * Returns the component type of this array type. | 
|      *  | 
|      * @throws ClassCastException | 
|      *             if this type is not an array. | 
|      */ | 
|     public static Type getArrayComponentType(Type array) { | 
|         return array instanceof GenericArrayType ? ((GenericArrayType) array).getGenericComponentType() : ((Class<?>) array).getComponentType(); | 
|     } | 
|   | 
|     /** | 
|      * Returns the element type of this collection type. | 
|      *  | 
|      * @throws IllegalArgumentException | 
|      *             if this type is not a collection. | 
|      */ | 
|     public static Type getCollectionElementType(Type context, Class<?> contextRawType) { | 
|         Type collectionType = getSupertype(context, contextRawType, Collection.class); | 
|   | 
|         if (collectionType instanceof WildcardType) { | 
|             collectionType = ((WildcardType) collectionType).getUpperBounds()[0]; | 
|         } | 
|         if (collectionType instanceof ParameterizedType) { | 
|             return ((ParameterizedType) collectionType).getActualTypeArguments()[0]; | 
|         } | 
|         return Object.class; | 
|     } | 
|   | 
|     /** | 
|      * Returns a two element array containing this map's key and value types in | 
|      * positions 0 and 1 respectively. | 
|      */ | 
|     public static Type[] getMapKeyAndValueTypes(Type context, Class<?> contextRawType) { | 
|         /* | 
|          * Work around a problem with the declaration of java.util.Properties. That | 
|          * class should extend Hashtable<String, String>, but it's declared to extend | 
|          * Hashtable<Object, Object>. | 
|          */ | 
|         if (context == Properties.class) { | 
|             return new Type[] { String.class, String.class }; // TODO: test subclasses of Properties! | 
|         } | 
|   | 
|         Type mapType = getSupertype(context, contextRawType, Map.class); | 
|         // TODO: strip wildcards? | 
|         if (mapType instanceof ParameterizedType) { | 
|             ParameterizedType mapParameterizedType = (ParameterizedType) mapType; | 
|             return mapParameterizedType.getActualTypeArguments(); | 
|         } | 
|         return new Type[] { Object.class, Object.class }; | 
|     } | 
|   | 
|     public static Type resolve(Type context, Class<?> contextRawType, Type toResolve) { | 
|         // this implementation is made a little more complicated in an attempt to avoid | 
|         // object-creation | 
|         while (true) { | 
|             if (toResolve instanceof TypeVariable) { | 
|                 TypeVariable<?> typeVariable = (TypeVariable<?>) toResolve; | 
|                 toResolve = resolveTypeVariable(context, contextRawType, typeVariable); | 
|                 if (toResolve == typeVariable) { | 
|                     return toResolve; | 
|                 } | 
|   | 
|             } else if (toResolve instanceof Class && ((Class<?>) toResolve).isArray()) { | 
|                 Class<?> original = (Class<?>) toResolve; | 
|                 Type componentType = original.getComponentType(); | 
|                 Type newComponentType = resolve(context, contextRawType, componentType); | 
|                 return componentType == newComponentType ? original : arrayOf(newComponentType); | 
|   | 
|             } else if (toResolve instanceof GenericArrayType) { | 
|                 GenericArrayType original = (GenericArrayType) toResolve; | 
|                 Type componentType = original.getGenericComponentType(); | 
|                 Type newComponentType = resolve(context, contextRawType, componentType); | 
|                 return componentType == newComponentType ? original : arrayOf(newComponentType); | 
|   | 
|             } else if (toResolve instanceof ParameterizedType) { | 
|                 ParameterizedType original = (ParameterizedType) toResolve; | 
|                 Type ownerType = original.getOwnerType(); | 
|                 Type newOwnerType = resolve(context, contextRawType, ownerType); | 
|                 boolean changed = newOwnerType != ownerType; | 
|   | 
|                 Type[] args = original.getActualTypeArguments(); | 
|                 for (int t = 0, length = args.length; t < length; t++) { | 
|                     Type resolvedTypeArgument = resolve(context, contextRawType, args[t]); | 
|                     if (resolvedTypeArgument != args[t]) { | 
|                         if (!changed) { | 
|                             args = args.clone(); | 
|                             changed = true; | 
|                         } | 
|                         args[t] = resolvedTypeArgument; | 
|                     } | 
|                 } | 
|   | 
|                 return changed ? newParameterizedTypeWithOwner(newOwnerType, original.getRawType(), args) : original; | 
|   | 
|             } else if (toResolve instanceof WildcardType) { | 
|                 WildcardType original = (WildcardType) toResolve; | 
|                 Type[] originalLowerBound = original.getLowerBounds(); | 
|                 Type[] originalUpperBound = original.getUpperBounds(); | 
|   | 
|                 if (originalLowerBound.length == 1) { | 
|                     Type lowerBound = resolve(context, contextRawType, originalLowerBound[0]); | 
|                     if (lowerBound != originalLowerBound[0]) { | 
|                         return supertypeOf(lowerBound); | 
|                     } | 
|                 } else if (originalUpperBound.length == 1) { | 
|                     Type upperBound = resolve(context, contextRawType, originalUpperBound[0]); | 
|                     if (upperBound != originalUpperBound[0]) { | 
|                         return subtypeOf(upperBound); | 
|                     } | 
|                 } | 
|                 return original; | 
|   | 
|             } else { | 
|                 return toResolve; | 
|             } | 
|         } | 
|     } | 
|   | 
|     static Type resolveTypeVariable(Type context, Class<?> contextRawType, TypeVariable<?> unknown) { | 
|         Class<?> declaredByRaw = declaringClassOf(unknown); | 
|   | 
|         // we can't reduce this further | 
|         if (declaredByRaw == null) { | 
|             return unknown; | 
|         } | 
|   | 
|         Type declaredBy = getGenericSupertype(context, contextRawType, declaredByRaw); | 
|         if (declaredBy instanceof ParameterizedType) { | 
|             int index = indexOf(declaredByRaw.getTypeParameters(), unknown); | 
|             return ((ParameterizedType) declaredBy).getActualTypeArguments()[index]; | 
|         } | 
|   | 
|         return unknown; | 
|     } | 
|   | 
|     private static int indexOf(Object[] array, Object toFind) { | 
|         for (int i = 0; i < array.length; i++) { | 
|             if (toFind.equals(array[i])) { | 
|                 return i; | 
|             } | 
|         } | 
|         throw new NoSuchElementException(); | 
|     } | 
|   | 
|     /** | 
|      * Returns the declaring class of {@code typeVariable}, or {@code null} if it | 
|      * was not declared by a class. | 
|      */ | 
|     private static Class<?> declaringClassOf(TypeVariable<?> typeVariable) { | 
|         GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration(); | 
|         return genericDeclaration instanceof Class ? (Class<?>) genericDeclaration : null; | 
|     } | 
|   | 
|     static void checkNotPrimitive(Type type) { | 
|         checkArgument(!(type instanceof Class<?>) || !((Class<?>) type).isPrimitive()); | 
|     } | 
|   | 
|     private static final class ParameterizedTypeImpl implements ParameterizedType, Serializable { | 
|         private final Type ownerType; | 
|         private final Type rawType; | 
|         private final Type[] typeArguments; | 
|   | 
|         public ParameterizedTypeImpl(Type ownerType, Type rawType, Type... typeArguments) { | 
|             // require an owner type if the raw type needs it | 
|             if (rawType instanceof Class<?>) { | 
|                 Class<?> rawTypeAsClass = (Class<?>) rawType; | 
|                 boolean isStaticOrTopLevelClass = Modifier.isStatic(rawTypeAsClass.getModifiers()) || rawTypeAsClass.getEnclosingClass() == null; | 
|                 checkArgument(ownerType != null || isStaticOrTopLevelClass); | 
|             } | 
|   | 
|             this.ownerType = ownerType == null ? null : canonicalize(ownerType); | 
|             this.rawType = canonicalize(rawType); | 
|             this.typeArguments = typeArguments.clone(); | 
|             for (int t = 0; t < this.typeArguments.length; t++) { | 
|                 checkNotNull(this.typeArguments[t]); | 
|                 checkNotPrimitive(this.typeArguments[t]); | 
|                 this.typeArguments[t] = canonicalize(this.typeArguments[t]); | 
|             } | 
|         } | 
|   | 
|         public Type[] getActualTypeArguments() { | 
|             return typeArguments.clone(); | 
|         } | 
|   | 
|         public Type getRawType() { | 
|             return rawType; | 
|         } | 
|   | 
|         public Type getOwnerType() { | 
|             return ownerType; | 
|         } | 
|   | 
|         @Override | 
|         public boolean equals(Object other) { | 
|             return other instanceof ParameterizedType && $Gson$Types.equals(this, (ParameterizedType) other); | 
|         } | 
|   | 
|         @Override | 
|         public int hashCode() { | 
|             return Arrays.hashCode(typeArguments) ^ rawType.hashCode() ^ hashCodeOrZero(ownerType); | 
|         } | 
|   | 
|         @Override | 
|         public String toString() { | 
|             StringBuilder stringBuilder = new StringBuilder(30 * (typeArguments.length + 1)); | 
|             stringBuilder.append(typeToString(rawType)); | 
|   | 
|             if (typeArguments.length == 0) { | 
|                 return stringBuilder.toString(); | 
|             } | 
|   | 
|             stringBuilder.append("<").append(typeToString(typeArguments[0])); | 
|             for (int i = 1; i < typeArguments.length; i++) { | 
|                 stringBuilder.append(", ").append(typeToString(typeArguments[i])); | 
|             } | 
|             return stringBuilder.append(">").toString(); | 
|         } | 
|   | 
|         private static final long serialVersionUID = 0; | 
|     } | 
|   | 
|     private static final class GenericArrayTypeImpl implements GenericArrayType, Serializable { | 
|         private final Type componentType; | 
|   | 
|         public GenericArrayTypeImpl(Type componentType) { | 
|             this.componentType = canonicalize(componentType); | 
|         } | 
|   | 
|         public Type getGenericComponentType() { | 
|             return componentType; | 
|         } | 
|   | 
|         @Override | 
|         public boolean equals(Object o) { | 
|             return o instanceof GenericArrayType && $Gson$Types.equals(this, (GenericArrayType) o); | 
|         } | 
|   | 
|         @Override | 
|         public int hashCode() { | 
|             return componentType.hashCode(); | 
|         } | 
|   | 
|         @Override | 
|         public String toString() { | 
|             return typeToString(componentType) + "[]"; | 
|         } | 
|   | 
|         private static final long serialVersionUID = 0; | 
|     } | 
|   | 
|     /** | 
|      * The WildcardType interface supports multiple upper bounds and multiple lower | 
|      * bounds. We only support what the Java 6 language needs - at most one bound. | 
|      * If a lower bound is set, the upper bound must be Object.class. | 
|      */ | 
|     private static final class WildcardTypeImpl implements WildcardType, Serializable { | 
|         private final Type upperBound; | 
|         private final Type lowerBound; | 
|   | 
|         public WildcardTypeImpl(Type[] upperBounds, Type[] lowerBounds) { | 
|             checkArgument(lowerBounds.length <= 1); | 
|             checkArgument(upperBounds.length == 1); | 
|   | 
|             if (lowerBounds.length == 1) { | 
|                 checkNotNull(lowerBounds[0]); | 
|                 checkNotPrimitive(lowerBounds[0]); | 
|                 checkArgument(upperBounds[0] == Object.class); | 
|                 this.lowerBound = canonicalize(lowerBounds[0]); | 
|                 this.upperBound = Object.class; | 
|   | 
|             } else { | 
|                 checkNotNull(upperBounds[0]); | 
|                 checkNotPrimitive(upperBounds[0]); | 
|                 this.lowerBound = null; | 
|                 this.upperBound = canonicalize(upperBounds[0]); | 
|             } | 
|         } | 
|   | 
|         public Type[] getUpperBounds() { | 
|             return new Type[] { upperBound }; | 
|         } | 
|   | 
|         public Type[] getLowerBounds() { | 
|             return lowerBound != null ? new Type[] { lowerBound } : EMPTY_TYPE_ARRAY; | 
|         } | 
|   | 
|         @Override | 
|         public boolean equals(Object other) { | 
|             return other instanceof WildcardType && $Gson$Types.equals(this, (WildcardType) other); | 
|         } | 
|   | 
|         @Override | 
|         public int hashCode() { | 
|             // this equals Arrays.hashCode(getLowerBounds()) ^ | 
|             // Arrays.hashCode(getUpperBounds()); | 
|             return (lowerBound != null ? 31 + lowerBound.hashCode() : 1) ^ (31 + upperBound.hashCode()); | 
|         } | 
|   | 
|         @Override | 
|         public String toString() { | 
|             if (lowerBound != null) { | 
|                 return "? super " + typeToString(lowerBound); | 
|             } else if (upperBound == Object.class) { | 
|                 return "?"; | 
|             } else { | 
|                 return "? extends " + typeToString(upperBound); | 
|             } | 
|         } | 
|   | 
|         private static final long serialVersionUID = 0; | 
|     } | 
| } |