actualTypes = act.getBindings().getTypeParameters();
for (int i = 0, len = expectedTypes.size(); i < len; ++i) {
JavaType exp2 = expectedTypes.get(i);
JavaType act2 = actualTypes.get(i);
if (!_verifyAndResolvePlaceholders(exp2, act2)) {
return false;
}
}
return true;
}
/**
* Method similar to {@link #constructSpecializedType}, but that creates a
* less-specific type of given type. Usually this is as simple as simply
* finding super-type with type erasure of superClass
, but
* there may be need for some additional work-arounds.
*
* @param superClass
*
* @since 2.7
*/
public JavaType constructGeneralizedType(JavaType baseType, Class> superClass)
{
// simple optimization to avoid costly introspection if type-erased type does NOT differ
final Class> rawBase = baseType.getRawClass();
if (rawBase == superClass) {
return baseType;
}
JavaType superType = baseType.findSuperType(superClass);
if (superType == null) {
// Most likely, caller did not verify sub/super-type relationship
if (!superClass.isAssignableFrom(rawBase)) {
throw new IllegalArgumentException(String.format(
"Class %s not a super-type of %s", superClass.getName(), baseType));
}
// 01-Nov-2015, tatu: Should never happen, but ch
throw new IllegalArgumentException(String.format(
"Internal error: class %s not included as super-type for %s",
superClass.getName(), baseType));
}
return superType;
}
/**
* Factory method for constructing a {@link JavaType} out of its canonical
* representation (see {@link JavaType#toCanonical()}).
*
* @param canonical Canonical string representation of a type
*
* @throws IllegalArgumentException If canonical representation is malformed,
* or class that type represents (including its generic parameters) is
* not found
*/
public JavaType constructFromCanonical(String canonical) throws IllegalArgumentException
{
return _parser.parse(canonical);
}
/**
* Method that is to figure out actual type parameters that given
* class binds to generic types defined by given (generic)
* interface or class.
* This could mean, for example, trying to figure out
* key and value types for Map implementations.
*
* @param type Sub-type (leaf type) that implements expType
*/
public JavaType[] findTypeParameters(JavaType type, Class> expType)
{
JavaType match = type.findSuperType(expType);
if (match == null) {
return NO_TYPES;
}
return match.getBindings().typeParameterArray();
}
/**
* @deprecated Since 2.7 resolve raw type first, then find type parameters
*/
@Deprecated // since 2.7
public JavaType[] findTypeParameters(Class> clz, Class> expType, TypeBindings bindings) {
return findTypeParameters(constructType(clz, bindings), expType);
}
/**
* @deprecated Since 2.7 resolve raw type first, then find type parameters
*/
@Deprecated // since 2.7
public JavaType[] findTypeParameters(Class> clz, Class> expType) {
return findTypeParameters(constructType(clz), expType);
}
/**
* Method that can be called to figure out more specific of two
* types (if they are related; that is, one implements or extends the
* other); or if not related, return the primary type.
*
* @param type1 Primary type to consider
* @param type2 Secondary type to consider
*
* @since 2.2
*/
public JavaType moreSpecificType(JavaType type1, JavaType type2)
{
if (type1 == null) {
return type2;
}
if (type2 == null) {
return type1;
}
Class> raw1 = type1.getRawClass();
Class> raw2 = type2.getRawClass();
if (raw1 == raw2) {
return type1;
}
// TODO: maybe try sub-classing, to retain generic types?
if (raw1.isAssignableFrom(raw2)) {
return type2;
}
return type1;
}
/*
/**********************************************************
/* Public factory methods
/**********************************************************
*/
public JavaType constructType(Type type) {
return _fromAny(null, type, EMPTY_BINDINGS);
}
public JavaType constructType(Type type, TypeBindings bindings) {
return _fromAny(null, type, bindings);
}
public JavaType constructType(TypeReference> typeRef)
{
// 19-Oct-2015, tatu: Simpler variant like so should work
return _fromAny(null, typeRef.getType(), EMPTY_BINDINGS);
// but if not, due to funky sub-classing, type variables, what follows
// is a more complete processing a la Java ClassMate.
/*
final Class> refdRawType = typeRef.getClass();
JavaType type = _fromClass(null, refdRawType, EMPTY_BINDINGS);
JavaType genType = type.findSuperType(TypeReference.class);
if (genType == null) { // sanity check; shouldn't occur
throw new IllegalArgumentException("Unparameterized GenericType instance ("+refdRawType.getName()+")");
}
TypeBindings b = genType.getBindings();
JavaType[] params = b.typeParameterArray();
if (params.length == 0) {
throw new IllegalArgumentException("Unparameterized GenericType instance ("+refdRawType.getName()+")");
}
return params[0];
*/
}
/**
* @deprecated Since 2.7 (accidentally removed in 2.7.0; added back in 2.7.1)
*/
@Deprecated
public JavaType constructType(Type type, Class> contextClass) {
JavaType contextType = (contextClass == null) ? null : constructType(contextClass);
return constructType(type, contextType);
}
/**
* @deprecated Since 2.7 (accidentally removed in 2.7.0; added back in 2.7.1)
*/
@Deprecated
public JavaType constructType(Type type, JavaType contextType) {
TypeBindings bindings;
if (contextType == null) {
bindings = TypeBindings.emptyBindings();
} else {
bindings = contextType.getBindings();
// 16-Nov-2016, tatu: Unfortunately as per [databind#1456] this can't
// be made to work for some cases used to work (even if accidentally);
// however, we can try a simple heuristic to increase chances of
// compatibility from 2.6 code
if (type.getClass() != Class.class) {
// Ok: so, ideally we would test super-interfaces if necessary;
// but let's assume most if not all cases are for classes.
while (bindings.isEmpty()) {
contextType = contextType.getSuperClass();
if (contextType == null) {
break;
}
bindings = contextType.getBindings();
}
}
}
return _fromAny(null, type, bindings);
}
/*
/**********************************************************
/* Direct factory methods
/**********************************************************
*/
/**
* Method for constructing an {@link ArrayType}.
*
* NOTE: type modifiers are NOT called on array type itself; but are called
* for element type (and other contained types)
*/
public ArrayType constructArrayType(Class> elementType) {
return ArrayType.construct(_fromAny(null, elementType, null), null);
}
/**
* Method for constructing an {@link ArrayType}.
*
* NOTE: type modifiers are NOT called on array type itself; but are called
* for contained types.
*/
public ArrayType constructArrayType(JavaType elementType) {
return ArrayType.construct(elementType, null);
}
/**
* Method for constructing a {@link CollectionType}.
*
* NOTE: type modifiers are NOT called on Collection type itself; but are called
* for contained types.
*/
public CollectionType constructCollectionType(Class extends Collection> collectionClass,
Class> elementClass) {
return constructCollectionType(collectionClass,
_fromClass(null, elementClass, EMPTY_BINDINGS));
}
/**
* Method for constructing a {@link CollectionType}.
*
* NOTE: type modifiers are NOT called on Collection type itself; but are called
* for contained types.
*/
public CollectionType constructCollectionType(Class extends Collection> collectionClass,
JavaType elementType) {
// 19-Oct-2015, tatu: Allow case of no-type-variables, since it seems likely to be
// a valid use case here
return (CollectionType) _fromClass(null, collectionClass,
TypeBindings.create(collectionClass, elementType));
}
/**
* Method for constructing a {@link CollectionLikeType}.
*
* NOTE: type modifiers are NOT called on constructed type itself; but are called
* for contained types.
*/
public CollectionLikeType constructCollectionLikeType(Class> collectionClass, Class> elementClass) {
return constructCollectionLikeType(collectionClass,
_fromClass(null, elementClass, EMPTY_BINDINGS));
}
/**
* Method for constructing a {@link CollectionLikeType}.
*
* NOTE: type modifiers are NOT called on constructed type itself; but are called
* for contained types.
*/
public CollectionLikeType constructCollectionLikeType(Class> collectionClass, JavaType elementType) {
JavaType type = _fromClass(null, collectionClass,
TypeBindings.createIfNeeded(collectionClass, elementType));
if (type instanceof CollectionLikeType) {
return (CollectionLikeType) type;
}
return CollectionLikeType.upgradeFrom(type, elementType);
}
/**
* Method for constructing a {@link MapType} instance
*
* NOTE: type modifiers are NOT called on constructed type itself; but are called
* for contained types.
*/
public MapType constructMapType(Class extends Map> mapClass,
Class> keyClass, Class> valueClass) {
JavaType kt, vt;
if (mapClass == Properties.class) {
kt = vt = CORE_TYPE_STRING;
} else {
kt = _fromClass(null, keyClass, EMPTY_BINDINGS);
vt = _fromClass(null, valueClass, EMPTY_BINDINGS);
}
return constructMapType(mapClass, kt, vt);
}
/**
* Method for constructing a {@link MapType} instance
*
* NOTE: type modifiers are NOT called on constructed type itself; but are called
* for contained types.
*/
public MapType constructMapType(Class extends Map> mapClass, JavaType keyType, JavaType valueType) {
return (MapType) _fromClass(null, mapClass,
TypeBindings.create(mapClass, keyType, valueType));
}
/**
* Method for constructing a {@link MapLikeType} instance
*
* NOTE: type modifiers are NOT called on constructed type itself; but are called
* for contained types.
*/
public MapLikeType constructMapLikeType(Class> mapClass, Class> keyClass, Class> valueClass) {
return constructMapLikeType(mapClass,
_fromClass(null, keyClass, EMPTY_BINDINGS),
_fromClass(null, valueClass, EMPTY_BINDINGS));
}
/**
* Method for constructing a {@link MapLikeType} instance
*
* NOTE: type modifiers are NOT called on constructed type itself; but are called
* for contained types.
*/
public MapLikeType constructMapLikeType(Class> mapClass, JavaType keyType, JavaType valueType) {
// 19-Oct-2015, tatu: Allow case of no-type-variables, since it seems likely to be
// a valid use case here
JavaType type = _fromClass(null, mapClass,
TypeBindings.createIfNeeded(mapClass, new JavaType[] { keyType, valueType }));
if (type instanceof MapLikeType) {
return (MapLikeType) type;
}
return MapLikeType.upgradeFrom(type, keyType, valueType);
}
/**
* Method for constructing a type instance with specified parameterization.
*
* NOTE: was briefly deprecated for 2.6.
*/
public JavaType constructSimpleType(Class> rawType, JavaType[] parameterTypes) {
return _fromClass(null, rawType, TypeBindings.create(rawType, parameterTypes));
}
/**
* Method for constructing a type instance with specified parameterization.
*
* @since 2.6
*
* @deprecated Since 2.7
*/
@Deprecated
public JavaType constructSimpleType(Class> rawType, Class> parameterTarget,
JavaType[] parameterTypes)
{
return constructSimpleType(rawType, parameterTypes);
}
/**
* @since 2.6
*/
public JavaType constructReferenceType(Class> rawType, JavaType referredType)
{
return ReferenceType.construct(rawType, null, // no bindings
null, null, // or super-class, interfaces?
referredType);
}
/**
* Method that use by core Databind functionality, and that should NOT be called
* by application code outside databind package.
*
* Unchecked here not only means that no checks are made as to whether given class
* might be non-simple type (like {@link CollectionType}) but also that most of supertype
* information is not gathered. This means that unless called on primitive types or
* {@link java.lang.String}, results are probably not what you want to use.
*
* @deprecated Since 2.8, to indicate users should never call this method.
*/
@Deprecated // since 2.8
public JavaType uncheckedSimpleType(Class> cls) {
// 18-Oct-2015, tatu: Not sure how much problem missing super-type info is here
return _constructSimple(cls, EMPTY_BINDINGS, null, null);
}
/**
* Factory method for constructing {@link JavaType} that
* represents a parameterized type. For example, to represent
* type List<Set<Integer>>
, you could
* call
*
* JavaType inner = TypeFactory.constructParametrizedType(Set.class, Set.class, Integer.class);
* return TypeFactory.constructParametrizedType(ArrayList.class, List.class, inner);
*
*
* The reason for first two arguments to be separate is that parameterization may
* apply to a super-type. For example, if generic type was instead to be
* constructed for ArrayList<Integer>
, the usual call would be:
*
* TypeFactory.constructParametrizedType(ArrayList.class, List.class, Integer.class);
*
* since parameterization is applied to {@link java.util.List}.
* In most cases distinction does not matter, but there are types where it does;
* one such example is parameterization of types that implement {@link java.util.Iterator}.
*
* NOTE: type modifiers are NOT called on constructed type.
*
* @param parametrized Actual full type
* @param parameterClasses Type parameters to apply
*
* @since 2.5 NOTE: was briefly deprecated for 2.6
*/
public JavaType constructParametricType(Class> parametrized, Class>... parameterClasses) {
int len = parameterClasses.length;
JavaType[] pt = new JavaType[len];
for (int i = 0; i < len; ++i) {
pt[i] = _fromClass(null, parameterClasses[i], EMPTY_BINDINGS);
}
return constructParametricType(parametrized, pt);
}
/**
* Factory method for constructing {@link JavaType} that
* represents a parameterized type. For example, to represent
* type List<Set<Integer>>
, you could
* call
*
* JavaType inner = TypeFactory.constructParametrizedType(Set.class, Set.class, Integer.class);
* return TypeFactory.constructParametrizedType(ArrayList.class, List.class, inner);
*
*
* The reason for first two arguments to be separate is that parameterization may
* apply to a super-type. For example, if generic type was instead to be
* constructed for ArrayList<Integer>
, the usual call would be:
*
* TypeFactory.constructParametrizedType(ArrayList.class, List.class, Integer.class);
*
* since parameterization is applied to {@link java.util.List}.
* In most cases distinction does not matter, but there are types where it does;
* one such example is parameterization of types that implement {@link java.util.Iterator}.
*
* NOTE: type modifiers are NOT called on constructed type.
*
* @param rawType Actual type-erased type
* @param parameterTypes Type parameters to apply
*
* @since 2.5 NOTE: was briefly deprecated for 2.6
*/
public JavaType constructParametricType(Class> rawType, JavaType... parameterTypes)
{
return _fromClass(null, rawType, TypeBindings.create(rawType, parameterTypes));
}
/**
* @since 2.5 -- but will probably deprecated in 2.7 or 2.8 (not needed with 2.7)
*/
public JavaType constructParametrizedType(Class> parametrized, Class> parametersFor,
JavaType... parameterTypes)
{
return constructParametricType(parametrized, parameterTypes);
}
/**
* @since 2.5 -- but will probably deprecated in 2.7 or 2.8 (not needed with 2.7)
*/
public JavaType constructParametrizedType(Class> parametrized, Class> parametersFor,
Class>... parameterClasses)
{
return constructParametricType(parametrized, parameterClasses);
}
/*
/**********************************************************
/* Direct factory methods for "raw" variants, used when
/* parameterization is unknown
/**********************************************************
*/
/**
* Method that can be used to construct "raw" Collection type; meaning that its
* parameterization is unknown.
* This is similar to using Object.class
parameterization,
* and is equivalent to calling:
*
* typeFactory.constructCollectionType(collectionClass, typeFactory.unknownType());
*
*
* This method should only be used if parameterization is completely unavailable.
*/
public CollectionType constructRawCollectionType(Class extends Collection> collectionClass) {
return constructCollectionType(collectionClass, unknownType());
}
/**
* Method that can be used to construct "raw" Collection-like type; meaning that its
* parameterization is unknown.
* This is similar to using Object.class
parameterization,
* and is equivalent to calling:
*
* typeFactory.constructCollectionLikeType(collectionClass, typeFactory.unknownType());
*
*
* This method should only be used if parameterization is completely unavailable.
*/
public CollectionLikeType constructRawCollectionLikeType(Class> collectionClass) {
return constructCollectionLikeType(collectionClass, unknownType());
}
/**
* Method that can be used to construct "raw" Map type; meaning that its
* parameterization is unknown.
* This is similar to using Object.class
parameterization,
* and is equivalent to calling:
*
* typeFactory.constructMapType(collectionClass, typeFactory.unknownType(), typeFactory.unknownType());
*
*
* This method should only be used if parameterization is completely unavailable.
*/
public MapType constructRawMapType(Class extends Map> mapClass) {
return constructMapType(mapClass, unknownType(), unknownType());
}
/**
* Method that can be used to construct "raw" Map-like type; meaning that its
* parameterization is unknown.
* This is similar to using Object.class
parameterization,
* and is equivalent to calling:
*
* typeFactory.constructMapLikeType(collectionClass, typeFactory.unknownType(), typeFactory.unknownType());
*
*
* This method should only be used if parameterization is completely unavailable.
*/
public MapLikeType constructRawMapLikeType(Class> mapClass) {
return constructMapLikeType(mapClass, unknownType(), unknownType());
}
/*
/**********************************************************
/* Low-level factory methods
/**********************************************************
*/
private JavaType _mapType(Class> rawClass, TypeBindings bindings,
JavaType superClass, JavaType[] superInterfaces)
{
JavaType kt, vt;
// 28-May-2015, tatu: Properties are special, as per [databind#810]; fake "correct" parameter sig
if (rawClass == Properties.class) {
kt = vt = CORE_TYPE_STRING;
} else {
List typeParams = bindings.getTypeParameters();
// ok to have no types ("raw")
switch (typeParams.size()) {
case 0: // acceptable?
kt = vt = _unknownType();
break;
case 2:
kt = typeParams.get(0);
vt = typeParams.get(1);
break;
default:
throw new IllegalArgumentException("Strange Map type "+rawClass.getName()+": can not determine type parameters");
}
}
return MapType.construct(rawClass, bindings, superClass, superInterfaces, kt, vt);
}
private JavaType _collectionType(Class> rawClass, TypeBindings bindings,
JavaType superClass, JavaType[] superInterfaces)
{
List typeParams = bindings.getTypeParameters();
// ok to have no types ("raw")
JavaType ct;
if (typeParams.isEmpty()) {
ct = _unknownType();
} else if (typeParams.size() == 1) {
ct = typeParams.get(0);
} else {
throw new IllegalArgumentException("Strange Collection type "+rawClass.getName()+": can not determine type parameters");
}
return CollectionType.construct(rawClass, bindings, superClass, superInterfaces, ct);
}
private JavaType _referenceType(Class> rawClass, TypeBindings bindings,
JavaType superClass, JavaType[] superInterfaces)
{
List typeParams = bindings.getTypeParameters();
// ok to have no types ("raw")
JavaType ct;
if (typeParams.isEmpty()) {
ct = _unknownType();
} else if (typeParams.size() == 1) {
ct = typeParams.get(0);
} else {
throw new IllegalArgumentException("Strange Reference type "+rawClass.getName()+": can not determine type parameters");
}
return ReferenceType.construct(rawClass, bindings, superClass, superInterfaces, ct);
}
/**
* Factory method to call when no special {@link JavaType} is needed,
* no generic parameters are passed. Default implementation may check
* pre-constructed values for "well-known" types, but if none found
* will simply call {@link #_newSimpleType}
*
* @since 2.7
*/
protected JavaType _constructSimple(Class> raw, TypeBindings bindings,
JavaType superClass, JavaType[] superInterfaces)
{
if (bindings.isEmpty()) {
JavaType result = _findWellKnownSimple(raw);
if (result != null) {
return result;
}
}
return _newSimpleType(raw, bindings, superClass, superInterfaces);
}
/**
* Factory method that is to create a new {@link SimpleType} with no
* checks whatsoever. Default implementation calls the single argument
* constructor of {@link SimpleType}.
*
* @since 2.7
*/
protected JavaType _newSimpleType(Class> raw, TypeBindings bindings,
JavaType superClass, JavaType[] superInterfaces)
{
return new SimpleType(raw, bindings, superClass, superInterfaces);
}
protected JavaType _unknownType() {
/* 15-Sep-2015, tatu: Prior to 2.7, we constructed new instance for each call.
* This may have been due to potential mutability of the instance; but that
* should not be issue any more, and creation is somewhat wasteful. So let's
* try reusing singleton/flyweight instance.
*/
return CORE_TYPE_OBJECT;
}
/**
* Helper method called to see if requested, non-generic-parameterized
* type is one of common, "well-known" types, instances of which are
* pre-constructed and do not need dynamic caching.
*
* @since 2.7
*/
protected JavaType _findWellKnownSimple(Class> clz) {
if (clz.isPrimitive()) {
if (clz == CLS_BOOL) return CORE_TYPE_BOOL;
if (clz == CLS_INT) return CORE_TYPE_INT;
if (clz == CLS_LONG) return CORE_TYPE_LONG;
} else {
if (clz == CLS_STRING) return CORE_TYPE_STRING;
if (clz == CLS_OBJECT) return CORE_TYPE_OBJECT; // since 2.7
}
return null;
}
/*
/**********************************************************
/* Actual type resolution, traversal
/**********************************************************
*/
/**
* Factory method that can be used if type information is passed
* as Java typing returned from getGenericXxx
methods
* (usually for a return or argument type).
*/
protected JavaType _fromAny(ClassStack context, Type type, TypeBindings bindings)
{
JavaType resultType;
// simple class?
if (type instanceof Class>) {
// Important: remove possible bindings since this is type-erased thingy
resultType = _fromClass(context, (Class>) type, EMPTY_BINDINGS);
}
// But if not, need to start resolving.
else if (type instanceof ParameterizedType) {
resultType = _fromParamType(context, (ParameterizedType) type, bindings);
}
else if (type instanceof JavaType) { // [databind#116]
// no need to modify further if we already had JavaType
return (JavaType) type;
}
else if (type instanceof GenericArrayType) {
resultType = _fromArrayType(context, (GenericArrayType) type, bindings);
}
else if (type instanceof TypeVariable>) {
resultType = _fromVariable(context, (TypeVariable>) type, bindings);
}
else if (type instanceof WildcardType) {
resultType = _fromWildcard(context, (WildcardType) type, bindings);
} else {
// sanity check
throw new IllegalArgumentException("Unrecognized Type: "+((type == null) ? "[null]" : type.toString()));
}
/* 21-Feb-2016, nateB/tatu: as per [databind#1129] (applied for 2.7.2),
* we do need to let all kinds of types to be refined, esp. for Scala module.
*/
if (_modifiers != null) {
TypeBindings b = resultType.getBindings();
if (b == null) {
b = EMPTY_BINDINGS;
}
for (TypeModifier mod : _modifiers) {
JavaType t = mod.modifyType(resultType, type, b, this);
if (t == null) {
throw new IllegalStateException(String.format(
"TypeModifier %s (of type %s) return null for type %s",
mod, mod.getClass().getName(), resultType));
}
resultType = t;
}
}
return resultType;
}
/**
* @param bindings Mapping of formal parameter declarations (for generic
* types) into actual types
*/
protected JavaType _fromClass(ClassStack context, Class> rawType, TypeBindings bindings)
{
// Very first thing: small set of core types we know well:
JavaType result = _findWellKnownSimple(rawType);
if (result != null) {
return result;
}
// Barring that, we may have recently constructed an instance
final Object key;
if ((bindings == null) || bindings.isEmpty()) {
key = rawType;
} else {
key = bindings.asKey(rawType);
}
result = _typeCache.get(key); // ok, cache object is synced
if (result != null) {
return result;
}
// 15-Oct-2015, tatu: recursive reference?
if (context == null) {
context = new ClassStack(rawType);
} else {
ClassStack prev = context.find(rawType);
if (prev != null) {
// Self-reference: needs special handling, then...
ResolvedRecursiveType selfRef = new ResolvedRecursiveType(rawType, EMPTY_BINDINGS);
prev.addSelfReference(selfRef);
return selfRef;
}
// no, but need to update context to allow for proper cycle resolution
context = context.child(rawType);
}
// First: do we have an array type?
if (rawType.isArray()) {
result = ArrayType.construct(_fromAny(context, rawType.getComponentType(), bindings),
bindings);
} else {
// If not, need to proceed by first resolving parent type hierarchy
JavaType superClass;
JavaType[] superInterfaces;
if (rawType.isInterface()) {
superClass = null;
superInterfaces = _resolveSuperInterfaces(context, rawType, bindings);
} else {
// Note: even Enums can implement interfaces, so can not drop those
superClass = _resolveSuperClass(context, rawType, bindings);
superInterfaces = _resolveSuperInterfaces(context, rawType, bindings);
}
// 19-Oct-2015, tatu: Bit messy, but we need to 'fix' java.util.Properties here...
if (rawType == Properties.class) {
result = MapType.construct(rawType, bindings, superClass, superInterfaces,
CORE_TYPE_STRING, CORE_TYPE_STRING);
}
// And then check what flavor of type we got. Start by asking resolved
// super-type if refinement is all that is needed?
else if (superClass != null) {
result = superClass.refine(rawType, bindings, superClass, superInterfaces);
}
// if not, perhaps we are now resolving a well-known class or interface?
if (result == null) {
result = _fromWellKnownClass(context, rawType, bindings, superClass, superInterfaces);
if (result == null) {
result = _fromWellKnownInterface(context, rawType, bindings, superClass, superInterfaces);
if (result == null) {
// but if nothing else, "simple" class for now:
result = _newSimpleType(rawType, bindings, superClass, superInterfaces);
}
}
}
}
context.resolveSelfReferences(result);
// 16-Jul-2016, tatu: [databind#1302] is solved different way, but ideally we shouldn't
// cache anything with partially resolved `ResolvedRecursiveType`... so maybe improve
if (!result.hasHandlers()) {
_typeCache.putIfAbsent(key, result); // cache object syncs
}
return result;
}
protected JavaType _resolveSuperClass(ClassStack context, Class> rawType, TypeBindings parentBindings)
{
Type parent = ClassUtil.getGenericSuperclass(rawType);
if (parent == null) {
return null;
}
return _fromAny(context, parent, parentBindings);
}
protected JavaType[] _resolveSuperInterfaces(ClassStack context, Class> rawType, TypeBindings parentBindings)
{
Type[] types = ClassUtil.getGenericInterfaces(rawType);
if (types == null || types.length == 0) {
return NO_TYPES;
}
int len = types.length;
JavaType[] resolved = new JavaType[len];
for (int i = 0; i < len; ++i) {
Type type = types[i];
resolved[i] = _fromAny(context, type, parentBindings);
}
return resolved;
}
/**
* Helper class used to check whether exact class for which type is being constructed
* is one of well-known base interfaces or classes that indicates alternate
* {@link JavaType} implementation.
*/
protected JavaType _fromWellKnownClass(ClassStack context, Class> rawType, TypeBindings bindings,
JavaType superClass, JavaType[] superInterfaces)
{
if (bindings == null) {
bindings = TypeBindings.emptyBindings();
}
// Quite simple when we resolving exact class/interface; start with that
if (rawType == Map.class) {
return _mapType(rawType, bindings, superClass, superInterfaces);
}
if (rawType == Collection.class) {
return _collectionType(rawType, bindings, superClass, superInterfaces);
}
// and since 2.6 one referential type
if (rawType == AtomicReference.class) {
return _referenceType(rawType, bindings, superClass, superInterfaces);
}
// 01-Nov-2015, tatu: As of 2.7, couple of potential `CollectionLikeType`s (like
// `Iterable`, `Iterator`), and `MapLikeType`s (`Map.Entry`) are not automatically
// detected, related to difficulties in propagating type upwards (Iterable, for
// example, is a weak, tag-on type). They may be detectable in future.
return null;
}
protected JavaType _fromWellKnownInterface(ClassStack context, Class> rawType, TypeBindings bindings,
JavaType superClass, JavaType[] superInterfaces)
{
// But that's not all: may be possible current type actually implements an
// interface type. So...
final int intCount = superInterfaces.length;
for (int i = 0; i < intCount; ++i) {
JavaType result = superInterfaces[i].refine(rawType, bindings, superClass, superInterfaces);
if (result != null) {
return result;
}
}
return null;
}
/**
* This method deals with parameterized types, that is,
* first class generic classes.
*/
protected JavaType _fromParamType(ClassStack context, ParameterizedType ptype,
TypeBindings parentBindings)
{
// Assumption here is we'll always get Class, not one of other Types
Class> rawType = (Class>) ptype.getRawType();
// 29-Oct-2015, tatu: For performance reasons, let's streamline handling of
// couple of not-so-useful parametric types
if (rawType == CLS_ENUM) {
return CORE_TYPE_ENUM;
}
if (rawType == CLS_COMPARABLE) {
return CORE_TYPE_COMPARABLE;
}
if (rawType == CLS_CLASS) {
return CORE_TYPE_CLASS;
}
// First: what is the actual base type? One odd thing is that 'getRawType'
// returns Type, not Class> as one might expect. But let's assume it is
// always of type Class: if not, need to add more code to resolve it to Class.
Type[] args = ptype.getActualTypeArguments();
int paramCount = (args == null) ? 0 : args.length;
TypeBindings newBindings;
if (paramCount == 0) {
newBindings = EMPTY_BINDINGS;
} else {
JavaType[] pt = new JavaType[paramCount];
for (int i = 0; i < paramCount; ++i) {
pt[i] = _fromAny(context, args[i], parentBindings);
}
newBindings = TypeBindings.create(rawType, pt);
}
return _fromClass(context, rawType, newBindings);
}
protected JavaType _fromArrayType(ClassStack context, GenericArrayType type, TypeBindings bindings)
{
JavaType elementType = _fromAny(context, type.getGenericComponentType(), bindings);
return ArrayType.construct(elementType, bindings);
}
protected JavaType _fromVariable(ClassStack context, TypeVariable> var, TypeBindings bindings)
{
// ideally should find it via bindings:
final String name = var.getName();
JavaType type = bindings.findBoundType(name);
if (type != null) {
return type;
}
// but if not, use bounds... note that approach here is simplistic; not taking
// into account possible multiple bounds, nor consider upper bounds.
if (bindings.hasUnbound(name)) {
return CORE_TYPE_OBJECT;
}
bindings = bindings.withUnboundVariable(name);
Type[] bounds = var.getBounds();
return _fromAny(context, bounds[0], bindings);
}
protected JavaType _fromWildcard(ClassStack context, WildcardType type, TypeBindings bindings)
{
/* Similar to challenges with TypeVariable, we may have multiple upper bounds.
* But it is also possible that if upper bound defaults to Object, we might
* want to consider lower bounds instead.
* For now, we won't try anything more advanced; above is just for future reference.
*/
return _fromAny(context, type.getUpperBounds()[0], bindings);
}
}