public abstract class AbstractTypes extends Object implements Types
Types
.
This class provides a skeletal implementation of the Types
interface. Specifically, it implements all
methods pertaining to §4.10 (subtyping) in the Java Language Specification (JLS). Concrete subclasses are expected to
implement the abstract methods in this class, which are responsible for creating appropriate type-mirror instances.
This class does not place any additional constraints on the concrete TypeMirror
and Element
implementations, so mutability and thread-safety are implementation-defined. However, this class crucially relies on
the equals
method being well-defined. That is, Element
objects that have equal names and equal
enclosing elements must compare equal. Likewise, TypeMirror
objects that contain equal values must compare
equal. In particular, multiple instances created by one of the get
-methods must compare equal when the given
arguments compare equal.
Besides subtype-related methods, this class also provides method
resolveActualTypeArguments(TypeElement, TypeMirror)
for resolving formal type parameters to actual type
arguments. For instance, given type List<String>
, this method determines the actual type argument for the
formal type parameter of Collection<E>
(that is, String
in this simple example).
Unless explicitly stated otherwise, all methods in this class expect non-null arguments. Passing null where not
expected will cause a NullPointerException
to be thrown. Implementations typically place additional
restrictions on method arguments not captured by the types of the formal parameters (which stem from
javax.lang.model
and its subpackages). While the details are implementation-defined, typically this means
that arguments must have been crated by the same implementation, or otherwise an IllegalArgumentException
will be thrown. Implementations must override requireValidType(TypeMirror)
and
requireValidElement(Element)
, as these methods are expected to perform any necessary validation.
Constructor and Description |
---|
AbstractTypes() |
Modifier and Type | Method and Description |
---|---|
Element |
asElement(TypeMirror type)
Returns the element corresponding to a type.
|
TypeMirror |
capture(TypeMirror type)
Returns the capture conversion of the given type, as specified by JLS §5.1.10.
|
protected abstract WildcardType |
capturedTypeArgument(TypeVariable typeVariable)
Returns the captured wildcard type argument of the given type variable, or null if the given type variable is not
the result of a capture conversion.
|
boolean |
contains(TypeMirror t1,
TypeMirror t2)
Returns whether the first type argument contains the second type argument, as specified by JLS §4.5.1.
|
protected abstract TypeVariable |
createTypeVariable(TypeParameterElement typeParameter,
WildcardType capturedTypeArgument)
Creates a new unfinished type variable for the given formal parameter.
|
TypeMirror |
erasure(TypeMirror type)
Returns the erasure of a type, as specified by JLS §4.6.
|
abstract IntersectionType |
getIntersectionType(TypeMirror... bounds)
Returns a new intersection type.
|
protected TypeVariable |
getTypeVariable(TypeParameterElement typeParameter,
TypeMirror upperBound,
TypeMirror lowerBound,
WildcardType capturedTypeArgument)
Returns a new type variable that corresponds to the given formal type parameter and that has the given actual
upper and lower bounds.
|
boolean |
isSameType(TypeMirror t1,
TypeMirror t2)
Returns whether the two given type arguments represent the same type.
|
boolean |
isSubtype(TypeMirror t1,
TypeMirror t2)
Returns whether the first type is a subtype of the second type, as specified by JLS §4.10.
|
protected abstract void |
requireValidElement(Element element)
Verifies that the given
Element is valid for use with this class. |
protected abstract void |
requireValidType(TypeMirror type)
Verifies that the given
TypeMirror is valid for use with this class, or that it is null . |
protected void |
requireValidTypes(TypeMirror[] types)
Verifies that the given array is non-null and contains valid types that are not null.
|
List<? extends TypeMirror> |
resolveActualTypeArguments(TypeElement typeElement,
TypeMirror subType)
Returns the actual type arguments of a type declaration given a subtype (typically with its own actual type
arguments).
|
protected abstract void |
setTypeVariableBounds(TypeVariable typeVariable,
TypeMirror upperBound,
TypeMirror lowerBound)
Sets the bounds of a type variable previously returned by
createTypeVariable(TypeParameterElement, WildcardType) . |
protected TypeMirror |
substitute(TypeMirror type,
Map<TypeParameterElement,? extends TypeMirror> substitutionMap)
Replaces formal type parameters in the given type.
|
String |
toString(TypeMirror type)
Returns the canonical string representation of the given type.
|
protected abstract TypeMirror |
typeMirror(Type type)
Returns a type mirror corresponding to the given Java reflection type.
|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
asMemberOf, boxedClass, directSupertypes, getArrayType, getDeclaredType, getDeclaredType, getNoType, getNullType, getPrimitiveType, getWildcardType, isAssignable, isSubsignature, unboxedType
protected abstract void requireValidElement(Element element)
Element
is valid for use with this class.
The meaning of valid is implementation-defined, but typically a valid Element
must have been created
by the implementation that belongs to the current AbstractTypes
instance.
element
- elementNullPointerException
- if the argument is nullIllegalArgumentException
- if the given Element
cannot be used with this classprotected abstract void requireValidType(@Nullable TypeMirror type)
TypeMirror
is valid for use with this class, or that it is null
.
The meaning of valid is implementation-defined, but typically a valid TypeMirror
must have been
created by the implementation that belongs to the current AbstractTypes
instance. A null
argument
is always valid. The rationale is that null
TypeMirror
arguments have a special meaning for some
methods such as Types.getWildcardType(TypeMirror, TypeMirror)
or
createTypeVariable(TypeParameterElement, WildcardType)
.
type
- type mirror, may be null
IllegalArgumentException
- if the given TypeMirror
instance is non-null and it cannot be used with
this classprotected final void requireValidTypes(TypeMirror[] types)
types
- array of typesNullPointerException
- if the given array or any of its elements are nullIllegalArgumentException
- if requireValidType(TypeMirror)
throws an exception for one of the
array elementsprotected abstract TypeMirror typeMirror(Type type)
Subclasses are required to return the appropriate DeclaredType
instances for the following
Class
instances:
Support for other types is not required and implementation-defined.
type
- type as represented by Java Reflection APIUnsupportedOperationException
- If the given type is not one of the above Class
objects and
this type-utilities implementation does not support mirroring arbitrary Java reflection types.protected TypeMirror substitute(TypeMirror type, Map<TypeParameterElement,? extends TypeMirror> substitutionMap)
This method requires that type
does not contain transitive references to itself, unless through
DeclaredType.asElement()
→ Element.asType()
or TypeVariable.asElement()
→
Element.asType()
. Otherwise, this method might run into an infinite recursion, resulting in
a StackOverflowError
.
Moreover, this method requires that any type variable transitively referenced by substitutionMap
must
not contain a transitive reference (through TypeVariable.getUpperBound()
or
TypeVariable.getLowerBound()
) to itself. Instead, any instance of TypeVariable
(transitively)
referenced by a value in substitutionMap
must be the result of Element.asType()
.
This method creates a fresh type variable for each formal type parameter that is to be substituted by a type
variable for the same formal type parameter. For instance, suppose T extends Object
is a formal type
parameter, and substitutionMap
specifies to replace it with the type variable T extends U<T>
. In
this case, createTypeVariable(TypeParameterElement, WildcardType)
will be called with the formal type
parameter T extends Object
as (first) argument. Once all fresh types have been created,
setTypeVariableBounds(TypeVariable, TypeMirror, TypeMirror)
will then be called with U<T>
as
upper bound, where T
is the fresh type variable T extends U<T>
.
type
- type in which the type parameters will be replaced recursively, guaranteed non-nullsubstitutionMap
- mapping from formal type parameters to substituted type, guaranteed non-null@Nullable public final List<? extends TypeMirror> resolveActualTypeArguments(TypeElement typeElement, TypeMirror subType)
This method "projects" the actual type arguments of subtype
, as well as all actual type arguments of
super types in the type hierarchy between typeElement
and subType
, onto the type declaration
represented by typeElement
.
For example, typeElement
may be the (generic) type declaration Comparable<T>
, and
subType
may be the (non-generic) type Integer
. The result in this case would be a singleton list
containing the type Integer
.
More generally, resolution works as follows: First, the shortest inheritance path from subType
to
typeElement
is found. Note that while Java allows multiple inheritance for interfaces, JLS §8.1.5
disallows inheriting from the same interface with different type parameters (both directly and transitively).
Hence, the shortest path contains all information that is necessary to resolve formal type parameters to actual
parameters. This method then propagates the actual type arguments bottom-up along the inheritance path.
Note that the inheritance path consists of DeclaredType
instances, and it may consist of generic types,
non-generic types, and raw types.
If the inheritance path contains a raw type before the last path element, this method proceeds
by using the "prototypical" type returned by Element.asType()
instead. Correspondingly, it is possible
that the returned list may contain type variables from a type declaration along the inheritance path. However, if
the last inheritance path element is a raw type, the returned list will be empty. Otherwise, if a
non-null non-empty List
is returned, it is guaranteed to have the same number of elements as
typeElement.getTypeParameters()
.
typeElement
- type declarationsubType
- potential subtype of typeElement
, must be a non-generic type declaration, raw type,
generic type declaration, or parameterized typetypeElement
(empty list if the last
path element in the inheritance path from subType
to typeElement
is a raw type), or
null
if subType
is not a subtype of typeElement
IllegalArgumentException
- if the arguments do not satisfy the constraints mentioned abovepublic final boolean isSubtype(TypeMirror t1, TypeMirror t2)
The subtype relationship is transitive and reflexive.
isSubtype
in interface Types
t1
- the first typet2
- the second typetrue
if and only if the first type is a subtype of the secondNullPointerException
- if an argument is nullIllegalArgumentException
- if given an executable or package typepublic final boolean contains(TypeMirror t1, TypeMirror t2)
Using the JLS notation, this method returns true if t2 <= t1
. As JLS §4.10 states, "subtyping does not
extend through parameterized types." Hence, this method is necessarily different from
isSubtype(TypeMirror, TypeMirror)
. In particular, the super-type relationship does not include types
with covariant type arguments.
contains
in interface Types
t1
- the first typet2
- the second typetrue
if and only if the first type contains the secondIllegalArgumentException
- if given an executable or package typepublic final TypeMirror erasure(TypeMirror type)
erasure
in interface Types
type
- the type to be erasedIllegalArgumentException
- if given a package typepublic final Element asElement(TypeMirror type)
The type may be a DeclaredType
or TypeVariable
. Returns null
if the type is not one
with a corresponding element.
public final boolean isSameType(TypeMirror t1, TypeMirror t2)
If either of the arguments to this method represents a wildcard, this method will return false. As a consequence, a wildcard is not the same type as itself.
isSameType
in interface Types
t1
- the first typet2
- the second typetrue
if and only if the two types are the samepublic final TypeMirror capture(TypeMirror type)
capture
in interface Types
type
- the type to be convertedIllegalArgumentException
- if given an executable or package typeprotected TypeVariable getTypeVariable(TypeParameterElement typeParameter, TypeMirror upperBound, TypeMirror lowerBound, @Nullable WildcardType capturedTypeArgument)
This method is primarily needed during capture conversion, in order to create a fresh type variable that
overrides the bounds of the formal type parameter it represents. This method is also called during substitution.
As an example, given a formal type parameter T extends Object
and an upper bound Number
, this
method returns the type variable T
with upper bound Number
.
This method is not suited for creating type variables with recursive type bounds if these bounds override the
bounds of the formal type parameter (as only happens during capture conversion). In order to create such a type
variable, this method may be used to create an interim type variable, where the (overridden) upper and lower
bounds should only reference the type variable returned by Element.asType()
. As a second
step, substitute(TypeMirror, Map)
may then be used to substitute the original type variable with the
interim type variable. The result will be a fresh type variable with the overridden bounds, and these bounds
will reference the fresh type variable instead of the original type variable.
typeParameter
- the formal type parameterupperBound
- the upper bound for the new type variable, may contain recursive references to
typeParameter.asType()
lowerBound
- the lower bound for the new type variable, may contain recursive references to
typeParameter.asType()
capturedTypeArgument
- the wildcard type argument that new type variable captures as part of a capture
conversion (§5.1.10 JLS), or null
if the new type variable is not the result of a capture conversionNullPointerException
- if any of the first three arguments is nullprotected abstract TypeVariable createTypeVariable(TypeParameterElement typeParameter, @Nullable WildcardType capturedTypeArgument)
Whenever this method is called within this class, the returned type variable is guaranteed to be passed to
setTypeVariableBounds(TypeVariable, TypeMirror, TypeMirror)
before being used as a TypeVariable
instance. That is, the returned type variable is considered to be under construction until being passed to
setTypeVariableBounds(TypeVariable, TypeMirror, TypeMirror)
, and only after that method call, the type
variable will have to satisfy the contract specified by interface TypeVariable
and its super-interfaces.
Before setTypeVariableBounds(TypeVariable, TypeMirror, TypeMirror)
is called on the returned
TypeVariable
, calling either TypeVariable.getUpperBound()
or TypeVariable.getLowerBound()
must trigger an IllegalStateException
.
Note that the previous paragraph does not guarantee that
setTypeVariableBounds(TypeVariable, TypeMirror, TypeMirror)
is always called on the newly returned
type-variable instance. If any exception occurs before the new type-variable could be used, then
setTypeVariableBounds(TypeVariable, TypeMirror, TypeMirror)
may not be called (even if the exception is
unrelated to the construction of the new type-variable instance).
The TypeVariable
interface does not provide access to captured wildcard type arguments. It can be
retrieved by calling capturedTypeArgument(TypeVariable)
instead.
typeParameter
- the formal type parametercapturedTypeArgument
- the wildcard type argument that new type variable captures as part of a capture
conversion (§5.1.10 JLS), or null
if the new type variable is not the result of a capture conversionTypeVariable
NullPointerException
- if typeParameter
is nullsetTypeVariableBounds(TypeVariable, TypeMirror, TypeMirror)
,
capturedTypeArgument(TypeVariable)
protected abstract void setTypeVariableBounds(TypeVariable typeVariable, TypeMirror upperBound, TypeMirror lowerBound)
createTypeVariable(TypeParameterElement, WildcardType)
.
Before an (unfinished) type-variable instance returned by
createTypeVariable(TypeParameterElement, WildcardType)
is used by this class, this method is guaranteed
to be called exactly once.
Implementations that create effectively immutable TypeMirror
instances may use this method to "freeze"
the given type-variable instance.
typeVariable
- type variable previously returned by
createTypeVariable(TypeParameterElement, WildcardType)
upperBound
- Upper bound for the given type variable. If no explicit upper bound is used, a
DeclaredType
representing Object
will be passed.lowerBound
- Lower bound for the given type variable. This may a NullType
instance, unless capture
conversion produced a type variable with a non-trivial lower bound.createTypeVariable(TypeParameterElement, WildcardType)
@Nullable protected abstract WildcardType capturedTypeArgument(TypeVariable typeVariable)
This method returns the wildcard type argument that was previously passed to
createTypeVariable(TypeParameterElement, WildcardType)
.
typeVariable
- the type variable that may be the result of a capture conversionpublic abstract IntersectionType getIntersectionType(TypeMirror... bounds)
bounds
- the bounds of the new intersection typeIllegalArgumentException
- if the given array is emptypublic final String toString(TypeMirror type)
type
- typeCopyright © 2014–2015. All rights reserved.