/** * Returns a type that is functionally equal but not necessarily equal according to {@link * Object#equals(Object) Object.equals()}. */ 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) { if (type instanceof ParameterizedTypeImpl) return type; ParameterizedType p = (ParameterizedType) type; return new ParameterizedTypeImpl(p.getOwnerType(), p.getRawType(), p.getActualTypeArguments()); } else if (type instanceof GenericArrayType) { if (type instanceof GenericArrayTypeImpl) return type; GenericArrayType g = (GenericArrayType) type; return new GenericArrayTypeImpl(g.getGenericComponentType()); } else if (type instanceof WildcardType) { if (type instanceof WildcardTypeImpl) return type; WildcardType w = (WildcardType) type; return new WildcardTypeImpl(w.getUpperBounds(), w.getLowerBounds()); } else { return type; // This type is unsupported! } }
private static boolean isAssignable(ParameterizedType lhsType, ParameterizedType rhsType){ if (lhsType.equals(rhsType)) { return true; } Type[] lhsTypeArguments = lhsType.getActualTypeArguments(); Type[] rhsTypeArguments = rhsType.getActualTypeArguments(); if (lhsTypeArguments.length != rhsTypeArguments.length) { return false; } for (int size = lhsTypeArguments.length, i = 0; i < size; ++i) { Type lhsArg = lhsTypeArguments[i]; Type rhsArg = rhsTypeArguments[i]; if (!lhsArg.equals(rhsArg) && !(lhsArg instanceof WildcardType && isAssignable((WildcardType) lhsArg, rhsArg))) { return false; } } return true; }
static boolean hasUnresolvableType(Type type) { if (type instanceof Class<?>) { return false; } if (type instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) type; for (Type typeArgument : parameterizedType.getActualTypeArguments()) { if (hasUnresolvableType(typeArgument)) { return true; } } return false; } if (type instanceof GenericArrayType) { return hasUnresolvableType(((GenericArrayType) type).getGenericComponentType()); } if (type instanceof TypeVariable) { return true; } if (type instanceof WildcardType) { return true; } String className = type == null ? "null" : type.getClass().getName(); throw new IllegalArgumentException("Expected a Class, ParameterizedType, or " + "GenericArrayType, but <" + type + "> is of type " + className); }
public void testGetSubtype_recursiveTypeBoundInSubtypeTranslatedAsIs() { class BaseWithTypeVar<T> {} class Outer<O> { class Sub<X> extends BaseWithTypeVar<List<X>> {} class Sub2<Y extends Sub2<Y>> extends BaseWithTypeVar<List<Y>> {} } ParameterizedType subtype = (ParameterizedType) new TypeToken<BaseWithTypeVar<List<?>>>() {} .getSubtype(Outer.Sub.class) .getType(); assertEquals(Outer.Sub.class, subtype.getRawType()); assertThat(subtype.getActualTypeArguments()[0]).isInstanceOf(WildcardType.class); ParameterizedType owner = (ParameterizedType) subtype.getOwnerType(); assertEquals(Outer.class, owner.getRawType()); // This returns a strange ? extends Sub2<Y> type, which isn't ideal. TypeToken<?> unused = new TypeToken<BaseWithTypeVar<List<?>>>() {}.getSubtype(Outer.Sub2.class); }
public static Type canonicalize(Type type) { if (type instanceof Class) { GenericArrayTypeImpl genericArrayTypeImpl; Class<?> c = (Class) type; if (c.isArray()) { genericArrayTypeImpl = new GenericArrayTypeImpl(C$Gson$Types.canonicalize(c .getComponentType())); } else { Object obj = c; } return genericArrayTypeImpl; } else if (type instanceof ParameterizedType) { ParameterizedType p = (ParameterizedType) type; return new ParameterizedTypeImpl(p.getOwnerType(), p.getRawType(), p .getActualTypeArguments()); } else if (type instanceof GenericArrayType) { return new GenericArrayTypeImpl(((GenericArrayType) type).getGenericComponentType()); } else { if (!(type instanceof WildcardType)) { return type; } WildcardType w = (WildcardType) type; return new WildcardTypeImpl(w.getUpperBounds(), w.getLowerBounds()); } }
/** * 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; } }
/** * Return true if any of the following conditions is met: * * <ul> * <li>'this' and {@code formalType} are equal * <li>{@code formalType} is {@code <? extends Foo>} and 'this' is a subtype of {@code Foo} * <li>{@code formalType} is {@code <? super Foo>} and 'this' is a supertype of {@code Foo} * </ul> */ private boolean is(Type formalType) { if (runtimeType.equals(formalType)) { return true; } if (formalType instanceof WildcardType) { // if "formalType" is <? extends Foo>, "this" can be: // Foo, SubFoo, <? extends Foo>, <? extends SubFoo>, <T extends Foo> or // <T extends SubFoo>. // if "formalType" is <? super Foo>, "this" can be: // Foo, SuperFoo, <? super Foo> or <? super SuperFoo>. return every(((WildcardType) formalType).getUpperBounds()).isSupertypeOf(runtimeType) && every(((WildcardType) formalType).getLowerBounds()).isSubtypeOf(runtimeType); } return false; }
/** * Returns the generic interfaces that this type directly {@code implements}. This method is * similar but different from {@link Class#getGenericInterfaces()}. For example, {@code new * TypeToken<List<String>>() {}.getGenericInterfaces()} will return a list that contains * {@code new TypeToken<Iterable<String>>() {}}; while {@code List.class.getGenericInterfaces()} * will return an array that contains {@code Iterable<T>}, where the {@code T} is the type * variable declared by interface {@code Iterable}. * * <p>If this type is a type variable or wildcard, its upper bounds are examined and those that * are either an interface or upper-bounded only by interfaces are returned. This means that the * returned types could include type variables too. */ final ImmutableList<TypeToken<? super T>> getGenericInterfaces() { if (runtimeType instanceof TypeVariable) { return boundsAsInterfaces(((TypeVariable<?>) runtimeType).getBounds()); } if (runtimeType instanceof WildcardType) { return boundsAsInterfaces(((WildcardType) runtimeType).getUpperBounds()); } ImmutableList.Builder<TypeToken<? super T>> builder = ImmutableList.builder(); for (Type interfaceType : getRawType().getGenericInterfaces()) { @SuppressWarnings("unchecked") // interface of T TypeToken<? super T> resolvedInterface = (TypeToken<? super T>) resolveSupertype(interfaceType); builder.add(resolvedInterface); } return builder.build(); }
public static Type getCollectionItemType(Type fieldType){ Type itemType = null; Class<?> clazz = null; if(fieldType instanceof ParameterizedType){ Type actualTypeArgument = ((ParameterizedType) fieldType).getActualTypeArguments()[0]; if(actualTypeArgument instanceof WildcardType){ WildcardType wildcardType = (WildcardType) actualTypeArgument; Type[] upperBounds = wildcardType.getUpperBounds(); if(upperBounds.length == 1){ actualTypeArgument = upperBounds[0]; } } itemType = actualTypeArgument; } else if(fieldType instanceof Class<?> // && !(clazz = (Class<?>) fieldType).getName().startsWith("java.")){ Type superClass = clazz.getGenericSuperclass(); itemType = TypeUtils.getCollectionItemType(superClass); } if(itemType == null){ itemType = Object.class; } return itemType; }
public static Class<?> getCollectionItemClass(Type fieldType){ if(fieldType instanceof ParameterizedType){ Class<?> itemClass; Type actualTypeArgument = ((ParameterizedType) fieldType).getActualTypeArguments()[0]; if(actualTypeArgument instanceof WildcardType){ WildcardType wildcardType = (WildcardType) actualTypeArgument; Type[] upperBounds = wildcardType.getUpperBounds(); if(upperBounds.length == 1){ actualTypeArgument = upperBounds[0]; } } if(actualTypeArgument instanceof Class){ itemClass = (Class<?>) actualTypeArgument; if(!Modifier.isPublic(itemClass.getModifiers())){ throw new JSONException("can not create ASMParser"); } } else{ throw new JSONException("can not create ASMParser"); } return itemClass; } return Object.class; }
/** * Returns the hashCode of {@code type}. */ public static int hashCode(Type type) { if (type instanceof Class) { // Class specifies hashCode(). return type.hashCode(); } else if (type instanceof ParameterizedType) { ParameterizedType p = (ParameterizedType) type; return Arrays.hashCode(p.getActualTypeArguments()) ^ p.getRawType().hashCode() ^ hashCodeOrZero(p.getOwnerType()); } else if (type instanceof GenericArrayType) { return hashCode(((GenericArrayType) type).getGenericComponentType()); } else if (type instanceof WildcardType) { WildcardType w = (WildcardType) type; return Arrays.hashCode(w.getLowerBounds()) ^ Arrays.hashCode(w.getUpperBounds()); } else { // This isn't a type we support. Probably a type variable return hashCodeOrZero(type); } }
@Override public Type responseType() { Type rawType = ((ParameterizedType) returnType).getRawType(); if (rawType.equals(Call.class) || rawType.equals(MockableCall.class) || rawType.equals(com.gabrielsamojlo.offit.Call.class)) { Type[] types = ((ParameterizedType) returnType).getActualTypeArguments(); Type paramType = types[0]; if (paramType instanceof WildcardType) { return ((WildcardType) paramType).getUpperBounds()[0]; } this.type = paramType; return paramType; } else { CallAdapter callAdapter = retrofit.nextCallAdapter(factory, returnType, annotations); return callAdapter.responseType(); } }
/** Returns the array type of {@code componentType}. */ static Type newArrayType(Type componentType) { if (componentType instanceof WildcardType) { WildcardType wildcard = (WildcardType) componentType; Type[] lowerBounds = wildcard.getLowerBounds(); checkArgument(lowerBounds.length <= 1, "Wildcard cannot have more than one lower bounds."); if (lowerBounds.length == 1) { return supertypeOf(newArrayType(lowerBounds[0])); } else { Type[] upperBounds = wildcard.getUpperBounds(); checkArgument(upperBounds.length == 1, "Wildcard should have only one upper bound."); return subtypeOf(newArrayType(upperBounds[0])); } } return JavaVersion.CURRENT.newArrayType(componentType); }
static Class<?> getRawType(Type type) { if (type == null) throw new NullPointerException("type == null"); if (type instanceof Class<?>) { // Type is a normal class. return (Class<?>) type; } 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(); if (!(rawType instanceof Class)) throw new IllegalArgumentException(); return (Class<?>) rawType; } if (type instanceof GenericArrayType) { Type componentType = ((GenericArrayType) type).getGenericComponentType(); return Array.newInstance(getRawType(componentType), 0).getClass(); } 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; } if (type instanceof WildcardType) { return getRawType(((WildcardType) type).getUpperBounds()[0]); } throw new IllegalArgumentException("Expected a Class, ParameterizedType, or " + "GenericArrayType, but <" + type + "> is of type " + type.getClass().getName()); }
/** * Returns the generic superclass of this type or {@code null} if the type represents * {@link Object} or an interface. This method is similar but different from * {@link Class#getGenericSuperclass}. For example, {@code new TypeToken<StringArrayList>() * {}.getGenericSuperclass()} will return {@code new TypeToken<ArrayList<String>>() {}}; while * {@code StringArrayList.class.getGenericSuperclass()} will return {@code ArrayList<E>}, where * {@code E} is the type variable declared by class {@code ArrayList}. * * <p>If this type is a type variable or wildcard, its first upper bound is examined and returned * if the bound is a class or extends from a class. This means that the returned type could be a * type variable too. */ @Nullable final TypeToken<? super T> getGenericSuperclass() { if (runtimeType instanceof TypeVariable) { // First bound is always the super class, if one exists. return boundAsSuperclass(((TypeVariable<?>) runtimeType).getBounds()[0]); } if (runtimeType instanceof WildcardType) { // wildcard has one and only one upper bound. return boundAsSuperclass(((WildcardType) runtimeType).getUpperBounds()[0]); } Type superclass = getRawType().getGenericSuperclass(); if (superclass == null) { return null; } @SuppressWarnings("unchecked") // super class of T TypeToken<? super T> superToken = (TypeToken<? super T>) resolveSupertype(superclass); return superToken; }
/** * Returns a type that is functionally equal but not necessarily equal * according to {@link Object#equals(Object) Object.equals()}. The returned * type is {@link 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 CompositeType) { return type; } 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; } }
/** * Returns the generic form of {@code superclass}. For example, if this is * {@code ArrayList<String>}, {@code Iterable<String>} is returned given the input * {@code Iterable.class}. */ public final TypeToken<? super T> getSupertype(Class<? super T> superclass) { checkArgument( this.someRawTypeIsSubclassOf(superclass), "%s is not a super class of %s", superclass, this); if (runtimeType instanceof TypeVariable) { return getSupertypeFromUpperBounds(superclass, ((TypeVariable<?>) runtimeType).getBounds()); } if (runtimeType instanceof WildcardType) { return getSupertypeFromUpperBounds(superclass, ((WildcardType) runtimeType).getUpperBounds()); } if (superclass.isArray()) { return getArraySupertype(superclass); } @SuppressWarnings("unchecked") // resolved supertype TypeToken<? super T> supertype = (TypeToken<? super T>) resolveSupertype(toGenericType(superclass).runtimeType); return supertype; }
/** * Returns subtype of {@code this} with {@code subclass} as the raw class. For example, if this is * {@code Iterable<String>} and {@code subclass} is {@code List}, {@code List<String>} is * returned. */ public final TypeToken<? extends T> getSubtype(Class<?> subclass) { checkArgument( !(runtimeType instanceof TypeVariable), "Cannot get subtype of type variable <%s>", this); if (runtimeType instanceof WildcardType) { return getSubtypeFromLowerBounds(subclass, ((WildcardType) runtimeType).getLowerBounds()); } // unwrap array type if necessary if (isArray()) { return getArraySubtype(subclass); } // At this point, it's either a raw class or parameterized type. checkArgument( getRawType().isAssignableFrom(subclass), "%s isn't a subclass of %s", subclass, this); Type resolvedTypeArgs = resolveTypeArgsForSubclass(subclass); @SuppressWarnings("unchecked") // guarded by the isAssignableFrom() statement above TypeToken<? extends T> subtype = (TypeToken<? extends T>) of(resolvedTypeArgs); return subtype; }
@Nullable private Class determineMapType(@NotNull Type type) { if (Map.class.isAssignableFrom(getType())) { Type mapType = GenericTypeReflector.getExactSuperType(type, Map.class); if (mapType instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) mapType; mapType = parameterizedType.getActualTypeArguments()[1]; if (mapType instanceof Class) { return (Class) mapType; } } if (mapType instanceof WildcardType) { return Object.class; } return GenericTypeReflector.erase(mapType); } return null; }
public void testGetSubtype_innerTypeOfGenericClassTranslatesOwnerTypeVars() { TypeToken<TwoTypeArgs<?, ?>.InnerType<?, ?>> supertype = new TypeToken<TwoTypeArgs<?, ?>.InnerType<?, ?>>() {}; TypeToken<StringForFirstTypeArg<Integer>.StringInnerType<Long>> subtype = new TypeToken<StringForFirstTypeArg<Integer>.StringInnerType<Long>>() {}; assertTrue(subtype.isSubtypeOf(supertype)); ParameterizedType actualSubtype = (ParameterizedType) supertype.getSubtype(subtype.getRawType()).getType(); assertEquals(StringForFirstTypeArg.StringInnerType.class, actualSubtype.getRawType()); assertThat(actualSubtype.getActualTypeArguments()[0]).isInstanceOf(WildcardType.class); ParameterizedType actualOwnerType = (ParameterizedType) actualSubtype.getOwnerType(); assertEquals(StringForFirstTypeArg.class, actualOwnerType.getRawType()); }
private static JavaType create(final ImplementClass implementClass, final Type type) { if (type instanceof Class<?>) { return new ClassJavaType(implementClass, (Class<?>) type); } else if (type instanceof TypeVariable<?>) { TypeVariable<?> variable = (TypeVariable<?>) type; return createByParamName(implementClass, variable); } else if (type instanceof GenericArrayType) { GenericArrayType arrayType = (GenericArrayType) type; return new ArrayJavaType(implementClass, arrayType); } else if (type instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) type; return new ParameterizedJavaType(implementClass, parameterizedType); } else if (type instanceof WildcardType) { WildcardType wildcardType = (WildcardType) type; return new WildcardJavaType(implementClass, wildcardType); } throw new IllegalArgumentException(type.getTypeName()); }
public static Class<?> getRawType(Type type) { if (type instanceof Class) { return (Class) type; } if (type instanceof ParameterizedType) { Type rawType = ((ParameterizedType) type).getRawType(); C$Gson$Preconditions.checkArgument(rawType instanceof Class); return (Class) rawType; } else if (type instanceof GenericArrayType) { return Array.newInstance(C$Gson$Types.getRawType(((GenericArrayType) type).getGenericComponentType()), 0).getClass(); } else { if (type instanceof TypeVariable) { return Object.class; } if (type instanceof WildcardType) { return C$Gson$Types.getRawType(((WildcardType) type).getUpperBounds()[0]); } throw new IllegalArgumentException("Expected a Class, ParameterizedType, or GenericArrayType, but <" + type + "> is of type " + (type == null ? "null" : type.getClass().getName())); } }
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); } }
private static Type getElementType(ParameterizedType type, int index) { Type elementType = type.getActualTypeArguments()[index]; if (elementType instanceof WildcardType) { WildcardType wildcardType = (WildcardType) elementType; return wildcardType.getUpperBounds()[0]; } return elementType; }
/** Returns true if {@code a} and {@code b} are equal. */ static boolean equals(Type a, Type b) { if (a == b) { return true; // Also handles (a == null && b == null). } else if (a instanceof Class) { return a.equals(b); // Class already specifies equals(). } else if (a instanceof ParameterizedType) { if (!(b instanceof ParameterizedType)) return false; 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 { return false; // This isn't a type we support! } }
static Type getParameterUpperBound(int index, ParameterizedType type) { Type[] types = type.getActualTypeArguments(); if (index < 0 || index >= types.length) { throw new IllegalArgumentException( "Index " + index + " not in range [0," + types.length + ") for " + type); } Type paramType = types[index]; if (paramType instanceof WildcardType) { return ((WildcardType) paramType).getUpperBounds()[0]; } return paramType; }
public ArrayListTypeFieldDeserializer(ParserConfig mapping, Class<?> clazz, FieldInfo fieldInfo){ super(clazz, fieldInfo); Type fieldType = fieldInfo.fieldType; if (fieldType instanceof ParameterizedType) { Type argType = ((ParameterizedType) fieldInfo.fieldType).getActualTypeArguments()[0]; if (argType instanceof WildcardType) { WildcardType wildcardType = (WildcardType) argType; Type[] upperBounds = wildcardType.getUpperBounds(); if (upperBounds.length == 1) { argType = upperBounds[0]; } } this.itemType = argType; } else { this.itemType = Object.class; } }
@Override public boolean equals(Object o) { if (o instanceof WildcardType) { WildcardType that = (WildcardType) o; return Arrays.equals(this.getLowerBounds(), that.getLowerBounds()) && Arrays.equals(this.getUpperBounds(), that.getUpperBounds()); } else return false; }
private static Class<?> getBestClassFromType(Type type) { if (type instanceof ParameterizedType) { Type[] types = ((ParameterizedType) type).getActualTypeArguments(); if (types != null && types.length > 0) { return (Class) types[0]; } } if (type instanceof WildcardType) { return (Class) ((WildcardType) type).getUpperBounds()[0]; } throw new Panic("not supported type: " + type); }
/** * 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; }
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(); 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); } }
/** * Returns the element type of this collection type. * * @throws IllegalArgumentException if this type is not a collection. */ public static Type collectionElementType(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; }