下面列出了怎么用java.lang.reflect.WildcardType的API类实例代码及写法,或者点击链接到github查看源代码。
/**
* 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;
}
/**
* 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;
}
/**
* Resolves the last type parameter of the parameterized {@code supertype}, based on the {@code
* genericContext}, into its upper bounds.
* <p/>
* Implementation copied from {@code
* retrofit.RestMethodInfo}.
*
* @param genericContext Ex. {@link java.lang.reflect.Field#getGenericType()}
* @param supertype Ex. {@code Decoder.class}
* @return in the example above, the type parameter of {@code Decoder}.
* @throws IllegalStateException if {@code supertype} cannot be resolved into a parameterized type
* using {@code context}.
*/
public static Type resolveLastTypeParameter(Type genericContext, Class<?> supertype)
throws IllegalStateException {
Type resolvedSuperType =
Types.getSupertype(genericContext, Types.getRawType(genericContext), supertype);
checkState(resolvedSuperType instanceof ParameterizedType,
"could not resolve %s into a parameterized type %s",
genericContext, supertype);
Type[] types = ParameterizedType.class.cast(resolvedSuperType).getActualTypeArguments();
for (int i = 0; i < types.length; i++) {
Type type = types[i];
if (type instanceof WildcardType) {
types[i] = ((WildcardType) type).getUpperBounds()[0];
}
}
return types[types.length - 1];
}
private Class<?> resolveClass(Type type, Class<?> subType) {
if (type instanceof Class) {
return (Class<?>) type;
} else if (type instanceof ParameterizedType) {
return resolveClass(((ParameterizedType) type).getRawType(), subType);
} else if (type instanceof GenericArrayType) {
GenericArrayType gat = (GenericArrayType) type;
Class<?> component = resolveClass(gat.getGenericComponentType(), subType);
return Array.newInstance(component, 0).getClass();
} else if (type instanceof TypeVariable<?>) {
TypeVariable<?> variable = (TypeVariable<?>) type;
Type resolvedType = getTypeVariableMap(subType).get(variable);
return (resolvedType == null) ? resolveClass(resolveBound(variable), subType)
: resolveClass(resolvedType, subType);
} else if (type instanceof WildcardType) {
WildcardType wcType = (WildcardType) type;
Type[] bounds = wcType.getLowerBounds().length == 0 ? wcType.getUpperBounds()
: wcType.getLowerBounds();
return resolveClass(bounds[0], subType);
}
// there are no more types in a standard JDK
throw new IllegalArgumentException("Unknown type: " + type);
}
/**
* Check lower bounded wildcard cases. Method is not called if upper bounds are not assignable.
* <p>
* When left is not lower bound - compatibility will be checked by type walker and when compatible always
* assignable. For example, String compatible (and assignable) with ? super String and Integer is not compatible
* with ? super Number (and not assignable).
* <p>
* Wen right is not lower bound, when left is then it will be never assignable. For example,
* ? super String is not assignable to String.
* <p>
* When both lower wildcards: lower bounds must be from one hierarchy and left type should be lower.
* For example, ? super Integer and ? super BigInteger are not assignable in spite of the fact that they
* share some common types. ? super Number is more specific then ? super Integer (super inverse meaning).
*
* @param one first type
* @param two second type
* @return true when left is assignable to right, false otherwise
*/
private boolean checkLowerBounds(final Type one, final Type two) {
final boolean res;
// ? super Object is impossible here due to types cleanup in tree walker
if (notLowerBounded(one)) {
// walker will check compatibility, and compatible type is always assignable to lower bounded wildcard
// e.g. Number assignable to ? super Number, but Integer not assignable to ? super Number
res = true;
} else if (notLowerBounded(two)) {
// lower bound could not be assigned to anything else (only opposite way is possible)
// for example, List<? super String> is not assignable to List<String>, but
// List<String> is assignable to List<? super String> (previous condition)
res = false;
} else {
// left type's bound must be lower: not a mistake! left (super inversion)!
res = TypeUtils.isAssignable(
((WildcardType) two).getLowerBounds()[0],
((WildcardType) one).getLowerBounds()[0]);
}
return res;
}
/**
* Adds any references learned by following a link from {@code cause} to {@code type}. This will
* dispatch according to the concrete {@code Type} implementation. See the other overloads of
* {@code addExposedTypes} for their details.
*/
private void addExposedTypes(Type type, Class<?> cause) {
if (type instanceof TypeVariable) {
LOG.debug("Adding exposed types from {}, which is a type variable", type);
addExposedTypes((TypeVariable) type, cause);
} else if (type instanceof WildcardType) {
LOG.debug("Adding exposed types from {}, which is a wildcard type", type);
addExposedTypes((WildcardType) type, cause);
} else if (type instanceof GenericArrayType) {
LOG.debug("Adding exposed types from {}, which is a generic array type", type);
addExposedTypes((GenericArrayType) type, cause);
} else if (type instanceof ParameterizedType) {
LOG.debug("Adding exposed types from {}, which is a parameterized type", type);
addExposedTypes((ParameterizedType) type, cause);
} else if (type instanceof Class) {
LOG.debug("Adding exposed types from {}, which is a class", type);
addExposedTypes((Class) type, cause);
} else {
throw new IllegalArgumentException("Unknown implementation of Type");
}
}
/**
* Get a {@link WildcardBounds} instance for the specified type, returning
* {@code null} if the specified type cannot be resolved to a {@link WildcardType}.
* @param type the source type
* @return a {@link WildcardBounds} instance or {@code null}
*/
public static WildcardBounds get(ResolvableType type) {
ResolvableType resolveToWildcard = type;
while (!(resolveToWildcard.getType() instanceof WildcardType)) {
if (resolveToWildcard == NONE) {
return null;
}
resolveToWildcard = resolveToWildcard.resolveType();
}
WildcardType wildcardType = (WildcardType) resolveToWildcard.type;
Kind boundsType = (wildcardType.getLowerBounds().length > 0 ? Kind.LOWER : Kind.UPPER);
Type[] bounds = boundsType == Kind.UPPER ? wildcardType.getUpperBounds() : wildcardType.getLowerBounds();
ResolvableType[] resolvableBounds = new ResolvableType[bounds.length];
for (int i = 0; i < bounds.length; i++) {
resolvableBounds[i] = ResolvableType.forType(bounds[i], type.variableResolver);
}
return new WildcardBounds(boundsType, resolvableBounds);
}
/**
* Adds any types exposed to this set. These will come from the (possibly absent) bounds on the
* wildcard.
*/
private void addExposedTypes(WildcardType type, Class<?> cause) {
visit(type);
for (Type lowerBound : type.getLowerBounds()) {
LOG.debug(
"Adding exposed types from {}, which is a type lower bound on wildcard type {}",
lowerBound,
type);
addExposedTypes(lowerBound, cause);
}
for (Type upperBound : type.getUpperBounds()) {
LOG.debug(
"Adding exposed types from {}, which is a type upper bound on wildcard type {}",
upperBound,
type);
addExposedTypes(upperBound, cause);
}
}
/**
* Returns whether the given type is one of the supported primitive classes like number and
* date/time, or is a wildcard of one.
*
* <p>A primitive class is any class for whom {@link Class#isPrimitive()} is true, as well as any
* classes of type: {@link Character}, {@link String}, {@link Integer}, {@link Long}, {@link
* Short}, {@link Byte}, {@link Float}, {@link Double}, {@link BigInteger}, {@link BigDecimal},
* {@link Boolean}, and {@link DateTime}.
*
* @param type type or {@code null} for {@code false} result
* @return whether it is a primitive
*/
public static boolean isPrimitive(Type type) {
// TODO(yanivi): support java.net.URI as primitive type?
if (type instanceof WildcardType) {
type = Types.getBound((WildcardType) type);
}
if (!(type instanceof Class<?>)) {
return false;
}
Class<?> typeClass = (Class<?>) type;
return typeClass.isPrimitive()
|| typeClass == Character.class
|| typeClass == String.class
|| typeClass == Integer.class
|| typeClass == Long.class
|| typeClass == Short.class
|| typeClass == Byte.class
|| typeClass == Float.class
|| typeClass == Double.class
|| typeClass == BigInteger.class
|| typeClass == BigDecimal.class
|| typeClass == DateTime.class
|| typeClass == Boolean.class;
}
public static Type a(Type type) {
if (type instanceof Class) {
c cVar;
Class cls = (Class) type;
if (cls.isArray()) {
cVar = new c(a(cls.getComponentType()));
} else {
Object obj = cls;
}
return cVar;
} else if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
return new d(parameterizedType.getOwnerType(), parameterizedType.getRawType(), parameterizedType.getActualTypeArguments());
} else if (type instanceof GenericArrayType) {
return new c(((GenericArrayType) type).getGenericComponentType());
} else {
if (!(type instanceof WildcardType)) {
return type;
}
WildcardType wildcardType = (WildcardType) type;
return new e(wildcardType.getUpperBounds(), wildcardType.getLowerBounds());
}
}
@Override
public GraphQLInputType getArgumentType(ArgContainer container) {
if (container == null) return null;
Object object = container.getRepresentativeObject();
if (object == null) return null;
if (object instanceof ParameterizedType
|| object instanceof WildcardType
|| object instanceof TypeVariable) {
return (GraphQLInputType) getContext().getParameterizedType(
object,
(Type) object,
TypeKind.INPUT_OBJECT);
}
return getContext().getInputType(object);
}
/**
* 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();
}
private boolean customComparatorAvailable(Class<?> providerClass) {
if (providerComparator != null) {
Type type = ((ParameterizedType)providerComparator.getClass()
.getGenericInterfaces()[0]).getActualTypeArguments()[0];
if (type instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType)type;
if (pt.getRawType() == ProviderInfo.class) {
Type type2 = pt.getActualTypeArguments()[0];
if (type2 == providerClass
|| type2 instanceof WildcardType
|| type2 instanceof ParameterizedType
&& ((ParameterizedType)type2).getRawType() == providerClass) {
return true;
}
}
} else if (type == Object.class) {
return true;
}
}
return false;
}
private Class<?> findRawType() {
if (getType() instanceof Class<?>) { // Plain old
return (Class<?>) getType();
} else if (getType() instanceof ParameterizedType) { // Nested type parameter
ParameterizedType parametrizedType = (ParameterizedType) getType();
Type rawType = parametrizedType.getRawType();
return (Class<?>) rawType;
} else if (getType() instanceof GenericArrayType) {
throw new IllegalStateException("cannot mock arrays, rejecting type: " + getType());
} else if (getType() instanceof WildcardType) {
throw new IllegalStateException(
"wildcarded instantiations are not allowed in java, rejecting type: " + getType());
} else {
throw new IllegalArgumentException("Could not decode raw type for: " + getType());
}
}
/**
* Learn, recursively, whether any of the type parameters associated with {@code type} are bound to variables.
*
* @param type the type to check for type variables
* @return boolean
* @since 3.2
*/
private static boolean containsTypeVariables(final Type type) {
if (type instanceof TypeVariable<?>) {
return true;
}
if (type instanceof Class<?>) {
return ((Class<?>) type).getTypeParameters().length > 0;
}
if (type instanceof ParameterizedType) {
for (final Type arg : ((ParameterizedType) type).getActualTypeArguments()) {
if (containsTypeVariables(arg)) {
return true;
}
}
return false;
}
if (type instanceof WildcardType) {
final WildcardType wild = (WildcardType) type;
return containsTypeVariables(TypeUtils.getImplicitLowerBounds(wild)[0])
|| containsTypeVariables(TypeUtils.getImplicitUpperBounds(wild)[0]);
}
return false;
}
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;
}
/**
* Called when types resolution finished in order to resolve placeholder with real type.
*
* @param bound real type
*/
public void resolve(final Type bound) {
if (upperBound != null) {
throw new IllegalArgumentException("Placeholder already resolved");
}
// reduce accuracy because otherwise infinite cycles are possible
// besides, placeholders may appear only on implemented interfaces and there exact type is not important
Class<?> res = GenericsUtils.resolveClass(bound);
if (root == null) {
// notify derived placeholders
if (placeholders != null) {
for (PlaceholderType placeholder : placeholders) {
placeholder.resolve(bound);
}
}
} else {
// try to use different type if possible (to avoid Some<Some> cases)
if (res.equals(root)
&& bound instanceof WildcardType && (((WildcardType) bound).getUpperBounds()).length > 1) {
// use second type by specificity
res = GenericsUtils.resolveClass(((WildcardType) bound).getUpperBounds()[1]);
}
}
this.upperBound = new Type[]{res};
}
/** Returns true if {@code a} and {@code b} are equal. */
public 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!
}
}
@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;
}
public static Type getCollectionElementType(Type type, Class class1)
{
Type type1 = b(type, class1, java/util/Collection);
if (type1 instanceof WildcardType)
{
type1 = ((WildcardType)type1).getUpperBounds()[0];
}
if (type1 instanceof ParameterizedType)
{
return ((ParameterizedType)type1).getActualTypeArguments()[0];
} else
{
return java/lang/Object;
}
}
public boolean equals(Object o) {
if (o instanceof WildcardType) {
WildcardType wt = (WildcardType) o;
return Arrays.equals(upperBounds, wt.getUpperBounds()) &&
Arrays.equals(lowerBounds, wt.getLowerBounds());
} else
return false;
}
private static void check2(Type t, String what) {
if (t instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) t;
check(pt.getActualTypeArguments(), "type argument", what);
} else if (t instanceof TypeVariable) {
TypeVariable<?> tv = (TypeVariable<?>) t;
check(tv.getBounds(), "bound", what);
GenericDeclaration gd = tv.getGenericDeclaration();
if (gd instanceof Type)
check((Type) gd, "declaration containing " + what);
} else if (t instanceof WildcardType) {
WildcardType wt = (WildcardType) t;
check(wt.getLowerBounds(), "lower bound", "wildcard type in " + what);
check(wt.getUpperBounds(), "upper bound", "wildcard type in " + what);
} else if (t instanceof Class<?>) {
Class<?> c = (Class<?>) t;
check(c.getGenericInterfaces(), "superinterface", c.toString());
check(c.getGenericSuperclass(), "superclass of " + c);
check(c.getTypeParameters(), "type parameter", c.toString());
} else if (t instanceof GenericArrayType) {
GenericArrayType gat = (GenericArrayType) t;
Type comp = gat.getGenericComponentType();
if (comp instanceof Class) {
fail("Type " + t + " uses GenericArrayType when plain " +
"array would do, in " + what);
} else
check(comp, "component type of " + what);
} else {
fail("TEST BUG: mutant Type " + t + " (a " + t.getClass().getName() + ")");
}
}
/**
* A parameterized event type is considered assignable to a parameterized observed event type if they have identical raw
* type and for each parameter:
*/
private static boolean parametersMatch(Type observedParameter, Type eventParameter) {
if (Types.isActualType(observedParameter) && Types.isActualType(eventParameter)) {
/*
* the observed event type parameter is an actual type with identical raw type to the event type parameter, and, if
* the type is parameterized, the
* event type parameter is assignable to the observed event type parameter according to these rules, or
*/
return matches(observedParameter, eventParameter);
}
if (observedParameter instanceof WildcardType && eventParameter instanceof WildcardType) {
/*
* both the observed event type parameter and the event type parameter are wildcards, and the event type parameter
* is assignable to the observed
* event type
*/
return CovariantTypes.isAssignableFrom(observedParameter, eventParameter);
}
if (observedParameter instanceof WildcardType) {
/*
* the observed event type parameter is a wildcard and the event type parameter is assignable to the upper bound, if
* any, of the wildcard and
* assignable from the lower bound, if any, of the wildcard, or
*/
return parametersMatch((WildcardType) observedParameter, eventParameter);
}
if (observedParameter instanceof TypeVariable<?>) {
/*
* the observed event type parameter is a type variable and the event type parameter is assignable to the upper
* bound, if any, of the type variable.
*/
return parametersMatch((TypeVariable<?>) observedParameter, eventParameter);
}
return false;
}
@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;
}
@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;
}
@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;
}
/**
* Visits the given types. Null types are ignored. This allows subclasses to call
* {@code visit(parameterizedType.getOwnerType())} safely without having to check nulls.
*/
public final void visit(Type... types) {
for (Type type : types) {
if (type == null || !visited.add(type)) {
// null owner type, or already visited;
continue;
}
boolean succeeded = false;
try {
if (type instanceof TypeVariable) {
visitTypeVariable((TypeVariable<?>) type);
} else if (type instanceof WildcardType) {
visitWildcardType((WildcardType) type);
} else if (type instanceof ParameterizedType) {
visitParameterizedType((ParameterizedType) type);
} else if (type instanceof Class) {
visitClass((Class<?>) type);
} else if (type instanceof GenericArrayType) {
visitGenericArrayType((GenericArrayType) type);
} else {
throw new AssertionError("Unknown type: " + type);
}
succeeded = true;
} finally {
if (!succeeded) { // When the visitation failed, we don't want to ignore the second.
visited.remove(type);
}
}
}
}
@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;
}
public boolean isParentId() {
if (!isTypeOf(IdRef.class)) {
return false;
}
ObjectModel objectModel = new ObjectModel(endpointClazz);
Type genericType = getGenericTypeAt(0);
if (genericType instanceof WildcardType) {
return false;
}
return objectModel.isAncestor((Class<?>) genericType);
}
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();
if (!(rawType instanceof Class)) {
throw new IllegalArgumentException();
}
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);
}
}