public WildcardTypeImpl(Type[] upperBounds, Type[] lowerBounds) { if (lowerBounds.length > 1) throw new IllegalArgumentException(); if (upperBounds.length != 1) throw new IllegalArgumentException(); if (lowerBounds.length == 1) { if (lowerBounds[0] == null) throw new NullPointerException(); checkNotPrimitive(lowerBounds[0]); if (upperBounds[0] != Object.class) throw new IllegalArgumentException(); this.lowerBound = canonicalize(lowerBounds[0]); this.upperBound = Object.class; } else { if (upperBounds[0] == null) throw new NullPointerException(); checkNotPrimitive(upperBounds[0]); this.lowerBound = null; this.upperBound = canonicalize(upperBounds[0]); } }
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; }
@Override public boolean equals(Object other) { return other instanceof ParameterizedType && Types.equals(this, (ParameterizedType) other); }
static Type getGenericSuperclass(Type type) { Class<?> rawType = Types.getRawType(type); return resolve(type, rawType, rawType.getGenericSuperclass()); }
/** * 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) { if (!supertype.isAssignableFrom(contextRawType)) throw new IllegalArgumentException(); return resolve(context, contextRawType, getGenericSupertype(context, contextRawType, supertype)); }
if (toResolve instanceof TypeVariable) { TypeVariable<?> typeVariable = (TypeVariable<?>) toResolve; toResolve = resolveTypeVariable(context, contextRawType, typeVariable); if (toResolve == typeVariable) return toResolve; Class<?> original = (Class<?>) toResolve; Type componentType = original.getComponentType(); Type newComponentType = resolve(context, contextRawType, componentType); return componentType == newComponentType ? original : arrayOf(newComponentType); Type newComponentType = resolve(context, contextRawType, componentType); return componentType == newComponentType ? original : arrayOf(newComponentType); Type newOwnerType = resolve(context, contextRawType, ownerType); boolean changed = newOwnerType != ownerType; Type resolvedTypeArgument = resolve(context, contextRawType, args[t]); if (resolvedTypeArgument != args[t]) { if (!changed) { Type lowerBound = resolve(context, contextRawType, originalLowerBound[0]); if (lowerBound != originalLowerBound[0]) { return supertypeOf(lowerBound); Type upperBound = resolve(context, contextRawType, originalUpperBound[0]);
public GenericArrayTypeImpl(Type componentType) { this.componentType = canonicalize(componentType); }
? ((ParameterizedTypeImpl) pb).typeArguments : pb.getActualTypeArguments(); return equal(pa.getOwnerType(), pb.getOwnerType()) && pa.getRawType().equals(pb.getRawType()) && Arrays.equals(aTypeArguments, bTypeArguments); GenericArrayType ga = (GenericArrayType) a; GenericArrayType gb = (GenericArrayType) b; return equals(ga.getGenericComponentType(), gb.getGenericComponentType());
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); } }
return rawType.getGenericInterfaces()[i]; } else if (toResolve.isAssignableFrom(interfaces[i])) { return getGenericSupertype(rawType.getGenericInterfaces()[i], interfaces[i], toResolve); return rawType.getGenericSuperclass(); } else if (toResolve.isAssignableFrom(rawSupertype)) { return getGenericSupertype(rawType.getGenericSuperclass(), rawSupertype, toResolve);
@Test public void arrayComponentType() throws Exception { assertThat(Types.arrayComponentType(String[][].class)).isEqualTo(String[].class); assertThat(Types.arrayComponentType(String[].class)).isEqualTo(String.class); Type arrayOfMapOfStringIntegerType = TypesTest.class.getDeclaredField( "arrayOfMapOfStringInteger").getGenericType(); Type mapOfStringIntegerType = TypesTest.class.getDeclaredField( "mapOfStringInteger").getGenericType(); assertThat(Types.arrayComponentType(arrayOfMapOfStringIntegerType)) .isEqualTo(mapOfStringIntegerType); }
@Test public void collectionElementType() throws Exception { Type arrayListOfMapOfStringIntegerType = TypesTest.class.getDeclaredField( "arrayListOfMapOfStringInteger").getGenericType(); Type mapOfStringIntegerType = TypesTest.class.getDeclaredField( "mapOfStringInteger").getGenericType(); assertThat(Types.collectionElementType(arrayListOfMapOfStringIntegerType, List.class)) .isEqualTo(mapOfStringIntegerType); }
/** * Given a parameterized type {@code A<B, C>}, returns B. If the specified type is not a generic * type, returns null. */ public static Type getFirstTypeArgument(Type type) throws Exception { if (!(type instanceof ParameterizedType)) return null; ParameterizedType ptype = (ParameterizedType) type; Type[] actualTypeArguments = ptype.getActualTypeArguments(); if (actualTypeArguments.length == 0) return null; return Types.canonicalize(actualTypeArguments[0]); }
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; if (ownerType == null && !isStaticOrTopLevelClass) throw new IllegalArgumentException(); } this.ownerType = ownerType == null ? null : canonicalize(ownerType); this.rawType = canonicalize(rawType); this.typeArguments = typeArguments.clone(); for (int t = 0; t < this.typeArguments.length; t++) { if (this.typeArguments[t] == null) throw new NullPointerException(); checkNotPrimitive(this.typeArguments[t]); this.typeArguments[t] = canonicalize(this.typeArguments[t]); } }
/** * 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! } }
@Override public boolean equals(Object other) { return other instanceof WildcardType && Types.equals(this, (WildcardType) other); }
type = Types.canonicalize(type);
@Override public boolean equals(Object o) { return o instanceof GenericArrayType && Types.equals(this, (GenericArrayType) o); }