package com.fasterxml.classmate;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.*;

import com.fasterxml.classmate.members.*;

public abstract class ResolvedType
    implements Type
{
    public final static ResolvedType[] NO_TYPES = new ResolvedType[0];

    protected final static RawConstructor[] NO_CONSTRUCTORS = new RawConstructor[0];
    protected final static RawField[] NO_FIELDS = new RawField[0];
    protected final static RawMethod[] NO_METHODS = new RawMethod[0];
    
    protected final Class<?> _erasedType;

    
Type bindings active when resolving members (methods, fields, constructors) of this type
/** * Type bindings active when resolving members (methods, fields, * constructors) of this type */
protected final TypeBindings _typeBindings; /* /********************************************************************** /* Life cycle /********************************************************************** */ protected ResolvedType(Class<?> cls, TypeBindings bindings) { _erasedType = cls; _typeBindings = (bindings == null) ? TypeBindings.emptyBindings() : bindings; }
Method that can be used to check if call to TypeResolver.resolveSubtype(ResolvedType, Class<?>) may ever succeed; if false, it will fail with an exception, if true, it may succeed.
/** * Method that can be used to check if call to {@link TypeResolver#resolveSubtype(ResolvedType, Class)} * may ever succeed; if false, it will fail with an exception, if true, it may succeed. */
public abstract boolean canCreateSubtypes();
Method that can be used to check if call to TypeResolver.resolveSubtype(ResolvedType, Class<?>) will succeed for specific type; if false, it will fail with an exception; if tru it will succeed.
/** * Method that can be used to check if call to {@link TypeResolver#resolveSubtype(ResolvedType, Class)} * will succeed for specific type; if false, it will fail with an exception; if tru it * will succeed. */
public final boolean canCreateSubtype(Class<?> subtype) { return canCreateSubtypes() && _erasedType.isAssignableFrom(subtype); } /* /********************************************************************** /* Accessors for related types /********************************************************************** */
Returns type-erased Class<?> that this resolved type has.
/** * Returns type-erased Class&lt;?&gt; that this resolved type has. */
public Class<?> getErasedType() { return _erasedType; }
Returns parent class of this type, if it has one; primitive types and interfaces have no parent class, nor does Object type Object. Also, placeholders for cyclic (recursive) types return null for this method.
/** * Returns parent class of this type, if it has one; primitive types * and interfaces have no parent class, nor does Object type * {@link java.lang.Object}. * Also, placeholders for cyclic (recursive) types return null for * this method. */
public abstract ResolvedType getParentClass();
Accessor that must be used to find out actual type in case of "self-reference"; case where type refers recursive to itself (like, T implements Comparable<T>). For all other types returns null but for self-references "real" type. Separate accessor is provided to avoid accidental infinite loops.
/** * Accessor that must be used to find out actual type in * case of "self-reference"; case where type refers * recursive to itself (like, <code>T implements Comparable&lt;T&gt;</code>). * For all other types returns null but for self-references "real" type. * Separate accessor is provided to avoid accidental infinite loops. */
public abstract ResolvedType getSelfReferencedType();
Method that can be used to access element type of array types; will return null for non-array types, and non-null type for array types.
/** * Method that can be used to access element type of array types; will return * null for non-array types, and non-null type for array types. */
public abstract ResolvedType getArrayElementType();
Returns ordered list of interfaces (in declaration order) that this type implements.
Returns:List of interfaces this type implements, if any; empty list if none
/** * Returns ordered list of interfaces (in declaration order) that this type * implements. * * @return List of interfaces this type implements, if any; empty list if none */
public abstract List<ResolvedType> getImplementedInterfaces();
Returns list of generic type declarations for this type, in order they are declared in class description.
/** * Returns list of generic type declarations for this type, in order they * are declared in class description. */
public List<ResolvedType> getTypeParameters() { return _typeBindings.getTypeParameters(); }
Method for accessing bindings of type variables to resolved types in context of this type. It has same number of entries as return List of getTypeParameters, accessible using declared name to which they bind; for example, Map has 2 type bindings; one for key type (name "K", from Map.java) and one for value type (name "V", from Map.java).
/** * Method for accessing bindings of type variables to resolved types in context * of this type. It has same number of entries as return List of * {@link #getTypeParameters}, accessible using declared name to which they * bind; for example, {@link java.util.Map} has 2 type bindings; one for * key type (name "K", from Map.java) and one for value type * (name "V", from Map.java). */
public TypeBindings getTypeBindings() { return _typeBindings; }
Method that will try to find type parameterization this type has for specified super type
Returns:List of type parameters for specified supertype (which may be empty, if supertype is not a parametric type); null if specified type is not a super type of this type
/** * Method that will try to find type parameterization this type * has for specified super type * * @return List of type parameters for specified supertype (which may * be empty, if supertype is not a parametric type); null if specified * type is not a super type of this type */
public List<ResolvedType> typeParametersFor(Class<?> erasedSupertype) { ResolvedType type = findSupertype(erasedSupertype); if (type != null) { return type.getTypeParameters(); } // nope; doesn't look like we extend or implement super type in question return null; }
Method for finding super type of this type that has specified type erased signature. If supertype is an interface which is implemented using multiple inheritance paths, preference is given to interfaces implemented "highest up the stack" (directly implemented interfaces over interfaces superclass implements).
/** * Method for finding super type of this type that has specified type * erased signature. If supertype is an interface which is implemented * using multiple inheritance paths, preference is given to interfaces * implemented "highest up the stack" (directly implemented interfaces * over interfaces superclass implements). */
public ResolvedType findSupertype(Class<?> erasedSupertype) { if (erasedSupertype == _erasedType) { return this; } // Check super interfaces first: if (erasedSupertype.isInterface()) { for (ResolvedType it : getImplementedInterfaces()) { ResolvedType type = it.findSupertype(erasedSupertype); if (type != null) { return type; } } } // and if not found, super class and its supertypes ResolvedType pc = getParentClass(); if (pc != null) { ResolvedType type = pc.findSupertype(erasedSupertype); if (type != null) { return type; } } // nope; doesn't look like we extend or implement super type in question return null; } /* /********************************************************************** /* Accessors for simple properties /********************************************************************** */ public abstract boolean isInterface(); public final boolean isConcrete() { return !isAbstract(); } public abstract boolean isAbstract();
Method that indicates whether this type is an array type.
/** * Method that indicates whether this type is an array type. */
public abstract boolean isArray();
Method that indicates whether this type is one of small number of primitive Java types; not including array types of primitive types but just basic primitive types.
/** * Method that indicates whether this type is one of small number of primitive * Java types; not including array types of primitive types but just basic * primitive types. */
public abstract boolean isPrimitive(); public final boolean isInstanceOf(Class<?> type) { return type.isAssignableFrom(_erasedType); } /* /********************************************************************** /* Accessors for raw (minimally procesed) members /********************************************************************** */ public List<RawConstructor> getConstructors() { return Collections.emptyList(); } public List<RawField> getMemberFields() { return Collections.emptyList(); } public List<RawMethod> getMemberMethods() { return Collections.emptyList(); } public List<RawField> getStaticFields() { return Collections.emptyList(); } public List<RawMethod> getStaticMethods() { return Collections.emptyList(); } /* /********************************************************************** /* String representations /********************************************************************** */
Method that returns full generic signature of the type; suitable as signature for things like ASM package.
/** * Method that returns full generic signature of the type; suitable * as signature for things like ASM package. */
public String getSignature() { StringBuilder sb = new StringBuilder(); return appendSignature(sb).toString(); }
Method that returns type erased signature of the type; suitable as non-generic signature some packages need
/** * Method that returns type erased signature of the type; suitable * as non-generic signature some packages need */
public String getErasedSignature() { StringBuilder sb = new StringBuilder(); return appendErasedSignature(sb).toString(); }
Human-readable full description of type, which includes specification of super types (in brief format)
/** * Human-readable full description of type, which includes specification * of super types (in brief format) */
public String getFullDescription() { StringBuilder sb = new StringBuilder(); return appendFullDescription(sb).toString(); }
Human-readable brief description of type, which does not include information about super types.
/** * Human-readable brief description of type, which does not include * information about super types. */
public String getBriefDescription() { StringBuilder sb = new StringBuilder(); return appendBriefDescription(sb).toString(); } public abstract StringBuilder appendBriefDescription(StringBuilder sb); public abstract StringBuilder appendFullDescription(StringBuilder sb); public abstract StringBuilder appendSignature(StringBuilder sb); public abstract StringBuilder appendErasedSignature(StringBuilder sb); /* /********************************************************************** /* Standard methods /********************************************************************** */ @Override public String toString() { return getBriefDescription(); } @Override public int hashCode() { return _erasedType.getName().hashCode() + _typeBindings.hashCode(); } @Override public boolean equals(Object o) { if (o == this) return true; // sub-types must be same: if (o == null || o.getClass() != getClass()) return false; // Should be possible to actually implement here... ResolvedType other = (ResolvedType) o; if (other._erasedType != _erasedType) { return false; } // and type bindings must match as well return _typeBindings.equals(other._typeBindings); } /* /********************************************************************** /* Helper methods for sub-classes; string construction /********************************************************************** */ protected StringBuilder _appendClassSignature(StringBuilder sb) { sb.append('L'); sb = _appendClassName(sb); int count = _typeBindings.size(); if (count > 0) { sb.append('<'); for (int i = 0; i < count; ++i) { sb = _typeBindings.getBoundType(i).appendErasedSignature(sb); } sb.append('>'); } sb.append(';'); return sb; } protected StringBuilder _appendErasedClassSignature(StringBuilder sb) { sb.append('L'); sb = _appendClassName(sb); sb.append(';'); return sb; } protected StringBuilder _appendClassDescription(StringBuilder sb) { sb.append(_erasedType.getName()); int count = _typeBindings.size(); if (count > 0) { sb.append('<'); for (int i = 0; i < count; ++i) { if (i > 0) { sb.append(','); } sb = _typeBindings.getBoundType(i).appendBriefDescription(sb); } sb.append('>'); } return sb; } protected StringBuilder _appendClassName(StringBuilder sb) { String name = _erasedType.getName(); for (int i = 0, len = name.length(); i < len; ++i) { char c = name.charAt(i); if (c == '.') c = '/'; sb.append(c); } return sb; } /* /********************************************************************** /* Helper methods for sub-classes; gathering members /********************************************************************** */
Params:
  • statics – Whether to return static methods (true) or member methods (false)
/** * @param statics Whether to return static methods (true) or member methods (false) */
protected RawField[] _getFields(boolean statics) { ArrayList<RawField> fields = new ArrayList<RawField>(); for (Field f : _erasedType.getDeclaredFields()) { // Only skip synthetic fields, which should not really be exposed if (!f.isSynthetic()) { if (Modifier.isStatic(f.getModifiers()) == statics) { fields.add(new RawField(this, f)); } } } if (fields.isEmpty()) { return NO_FIELDS; } return fields.toArray(new RawField[0]); }
Params:
  • statics – Whether to return static methods (true) or member methods (false)
/** * @param statics Whether to return static methods (true) or member methods (false) */
protected RawMethod[] _getMethods(boolean statics) { ArrayList<RawMethod> methods = new ArrayList<RawMethod>(); for (Method m : _erasedType.getDeclaredMethods()) { // Only skip synthetic fields, which should not really be exposed if (!m.isSynthetic()) { if (Modifier.isStatic(m.getModifiers()) == statics) { methods.add(new RawMethod(this, m)); } } } if (methods.isEmpty()) { return NO_METHODS; } return methods.toArray(new RawMethod[0]); } protected RawConstructor[] _getConstructors() { ArrayList<RawConstructor> ctors = new ArrayList<RawConstructor>(); for (Constructor<?> c : _erasedType.getDeclaredConstructors()) { // Only skip synthetic fields, which should not really be exposed if (!c.isSynthetic()) { ctors.add(new RawConstructor(this, c)); } } if (ctors.isEmpty()) { return NO_CONSTRUCTORS; } return ctors.toArray(new RawConstructor[0]); } }