/** * Determine whether the underlying type represents a wildcard * without specific bounds (i.e., equal to {@code ? extends Object}). */ private boolean isWildcardWithoutBounds() { if (this.type instanceof WildcardType) { WildcardType wt = (WildcardType) this.type; if (wt.getLowerBounds().length == 0) { Type[] upperBounds = wt.getUpperBounds(); if (upperBounds.length == 0 || (upperBounds.length == 1 && Object.class == upperBounds[0])) { return true; } } } return false; }
/** * @return The first bound, either a type or a reference to a TypeVariable */ public Type firstBound() { Type[] lowerBounds = wildcard.getLowerBounds(); Type[] upperBounds = wildcard.getUpperBounds(); return lowerBounds.length != 0 ? lowerBounds[0] : upperBounds[0]; }
@Override public boolean equals(Object obj) { if (obj instanceof WildcardType) { WildcardType that = (WildcardType) obj; return lowerBounds.equals(Arrays.asList(that.getLowerBounds())) && upperBounds.equals(Arrays.asList(that.getUpperBounds())); } return false; }
/** * <p>Returns an array containing a single value of {@code null} if * {@link WildcardType#getLowerBounds()} returns an empty array. Otherwise, * it returns the result of {@link WildcardType#getLowerBounds()}.</p> * * @param wildcardType the subject wildcard type, not {@code null} * @return a non-empty array containing the lower bounds of the wildcard * type. */ public static Type[] getImplicitLowerBounds(final WildcardType wildcardType) { Validate.notNull(wildcardType, "wildcardType is null"); final Type[] bounds = wildcardType.getLowerBounds(); return bounds.length == 0 ? new Type[] { null } : bounds; }
@Override void visitWildcardType(WildcardType fromWildcardType) { if (!(to instanceof WildcardType)) { return; // okay to say <?> is anything } WildcardType toWildcardType = (WildcardType) to; Type[] fromUpperBounds = fromWildcardType.getUpperBounds(); Type[] toUpperBounds = toWildcardType.getUpperBounds(); Type[] fromLowerBounds = fromWildcardType.getLowerBounds(); Type[] toLowerBounds = toWildcardType.getLowerBounds(); checkArgument( fromUpperBounds.length == toUpperBounds.length && fromLowerBounds.length == toLowerBounds.length, "Incompatible type: %s vs. %s", fromWildcardType, to); for (int i = 0; i < fromUpperBounds.length; i++) { populateTypeMappings(mappings, fromUpperBounds[i], toUpperBounds[i]); } for (int i = 0; i < fromLowerBounds.length; i++) { populateTypeMappings(mappings, fromLowerBounds[i], toLowerBounds[i]); } }
/** * {@inheritDoc} */ public TypeList.Generic getLowerBounds() { return new WildcardLowerBoundTypeList(wildcardType.getLowerBounds(), annotationReader); }
private static WildcardType canonicalizeWildcardType( TypeVariable<?> declaration, WildcardType type) { Type[] declared = declaration.getBounds(); List<Type> upperBounds = new ArrayList<>(); for (Type bound : type.getUpperBounds()) { if (!any(declared).isSubtypeOf(bound)) { upperBounds.add(canonicalizeWildcardsInType(bound)); } } return new Types.WildcardTypeImpl(type.getLowerBounds(), upperBounds.toArray(new Type[0])); }
@Override public boolean equals(Object obj) { if (obj instanceof WildcardType) { WildcardType that = (WildcardType) obj; return lowerBounds.equals(Arrays.asList(that.getLowerBounds())) && upperBounds.equals(Arrays.asList(that.getUpperBounds())); } return false; }
private WildcardType resolveWildcardType(WildcardType type) { Type[] lowerBounds = type.getLowerBounds(); Type[] upperBounds = type.getUpperBounds(); return new Types.WildcardTypeImpl(resolveTypes(lowerBounds), resolveTypes(upperBounds)); }
private void validateNoTypeParameterOnWildcardType(WildcardType wildcard, List<Throwable> errors) { for (Type each : wildcard.getUpperBounds()) { validateNoTypeParameterOnType(each, errors); } for (Type each : wildcard.getLowerBounds()) { validateNoTypeParameterOnType(each, errors); } }
private static WildcardType canonicalizeWildcardType( TypeVariable<?> declaration, WildcardType type) { Type[] declared = declaration.getBounds(); List<Type> upperBounds = new ArrayList<>(); for (Type bound : type.getUpperBounds()) { if (!any(declared).isSubtypeOf(bound)) { upperBounds.add(canonicalizeWildcardsInType(bound)); } } return new Types.WildcardTypeImpl(type.getLowerBounds(), upperBounds.toArray(new Type[0])); }
/** * 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} */ @Nullable 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); }
/** * 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); checkArgument( subtype.isSubtypeOf(this), "%s does not appear to be a subtype of %s", subtype, this); return subtype; }
/** 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); }
private WildcardType resolveWildcardType(WildcardType type) { Type[] lowerBounds = type.getLowerBounds(); Type[] upperBounds = type.getUpperBounds(); return new Types.WildcardTypeImpl(resolveTypes(lowerBounds), resolveTypes(upperBounds)); }
static TypeName get(WildcardType wildcardName, Map<Type, TypeVariableName> map) { return new WildcardTypeName( list(wildcardName.getUpperBounds(), map), list(wildcardName.getLowerBounds(), map)); } }
private WildcardType resolveWildcardType(WildcardType type) { Type[] lowerBounds = type.getLowerBounds(); Type[] upperBounds = type.getUpperBounds(); return new Types.WildcardTypeImpl(resolveTypes(lowerBounds), resolveTypes(upperBounds)); }
private static void assertEqualWildcardType(WildcardType expected, WildcardType actual) { assertEquals(expected.toString(), actual.toString()); assertEquals(actual.toString(), expected.hashCode(), actual.hashCode()); assertThat(actual.getLowerBounds()) .asList() .containsExactlyElementsIn(asList(expected.getLowerBounds())) .inOrder(); assertThat(actual.getUpperBounds()) .asList() .containsExactlyElementsIn(asList(expected.getUpperBounds())) .inOrder(); }
public void testWithGenericLowerBoundInWildcard() throws Exception { WildcardType wildcardType = (WildcardType) new WithGenericBound<String>() {}.getTargetType("withWildcardLowerBound"); assertEquals(String.class, wildcardType.getLowerBounds()[0]); }
@Test public void wildcardType() throws Exception { ParameterizedType typeSource = (ParameterizedType) SerializableTypeWrapper.forField(Fields.class.getField("wildcardType")); WildcardType type = (WildcardType) typeSource.getActualTypeArguments()[0]; assertThat(type.toString(), equalTo("? extends java.lang.CharSequence")); assertSerializable(type); assertSerializable(type.getLowerBounds()); assertSerializable(type.getUpperBounds()); }