package com.fasterxml.jackson.databind.type;

import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.lang.reflect.*;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.util.ArrayBuilders;
import com.fasterxml.jackson.databind.util.ClassUtil;
import com.fasterxml.jackson.databind.util.LRUMap;

Class used for creating concrete JavaType instances, given various inputs.

Instances of this class are accessible using ObjectMapper as well as many objects it constructs (like DeserializationConfig and SerializationConfig)), but usually those objects also expose convenience methods (constructType). So, you can do for example:

  JavaType stringType = mapper.constructType(String.class);
However, more advanced methods are only exposed by factory so that you may need to use:
  JavaType stringCollection = mapper.getTypeFactory().constructCollectionType(List.class, String.class);
/** * Class used for creating concrete {@link JavaType} instances, * given various inputs. *<p> * Instances of this class are accessible using {@link com.fasterxml.jackson.databind.ObjectMapper} * as well as many objects it constructs (like * {@link com.fasterxml.jackson.databind.DeserializationConfig} and * {@link com.fasterxml.jackson.databind.SerializationConfig})), * but usually those objects also * expose convenience methods (<code>constructType</code>). * So, you can do for example: *<pre> * JavaType stringType = mapper.constructType(String.class); *</pre> * However, more advanced methods are only exposed by factory so that you * may need to use: *<pre> * JavaType stringCollection = mapper.getTypeFactory().constructCollectionType(List.class, String.class); *</pre> */
@SuppressWarnings({"rawtypes" }) public class TypeFactory // note: was final in 2.9, removed from 2.10 implements java.io.Serializable { private static final long serialVersionUID = 1L; private final static JavaType[] NO_TYPES = new JavaType[0];
Globally shared singleton. Not accessed directly; non-core code should use per-ObjectMapper instance (via configuration objects). Core Jackson code uses defaultInstance for accessing it.
/** * Globally shared singleton. Not accessed directly; non-core * code should use per-ObjectMapper instance (via configuration objects). * Core Jackson code uses {@link #defaultInstance} for accessing it. */
protected final static TypeFactory instance = new TypeFactory(); protected final static TypeBindings EMPTY_BINDINGS = TypeBindings.emptyBindings(); /* /********************************************************** /* Constants for "well-known" classes /********************************************************** */ // // // Let's assume that a small set of core primitive/basic types // // // will not be modified, and can be freely shared to streamline // // // parts of processing private final static Class<?> CLS_STRING = String.class; private final static Class<?> CLS_OBJECT = Object.class; private final static Class<?> CLS_COMPARABLE = Comparable.class; private final static Class<?> CLS_CLASS = Class.class; private final static Class<?> CLS_ENUM = Enum.class; private final static Class<?> CLS_JSON_NODE = JsonNode.class; // since 2.10 private final static Class<?> CLS_BOOL = Boolean.TYPE; private final static Class<?> CLS_INT = Integer.TYPE; private final static Class<?> CLS_LONG = Long.TYPE; /* /********************************************************** /* Cached pre-constructed JavaType instances /********************************************************** */ // note: these are primitive, hence no super types protected final static SimpleType CORE_TYPE_BOOL = new SimpleType(CLS_BOOL); protected final static SimpleType CORE_TYPE_INT = new SimpleType(CLS_INT); protected final static SimpleType CORE_TYPE_LONG = new SimpleType(CLS_LONG); // and as to String... well, for now, ignore its super types protected final static SimpleType CORE_TYPE_STRING = new SimpleType(CLS_STRING); // @since 2.7 protected final static SimpleType CORE_TYPE_OBJECT = new SimpleType(CLS_OBJECT);
Cache Comparable because it is both parameteric (relatively costly to resolve) and mostly useless (no special handling), better handle directly
Since:2.7
/** * Cache {@link Comparable} because it is both parameteric (relatively costly to * resolve) and mostly useless (no special handling), better handle directly * * @since 2.7 */
protected final static SimpleType CORE_TYPE_COMPARABLE = new SimpleType(CLS_COMPARABLE);
Cache Enum because it is parametric AND self-referential (costly to resolve) and useless in itself (no special handling).
Since:2.7
/** * Cache {@link Enum} because it is parametric AND self-referential (costly to * resolve) and useless in itself (no special handling). * * @since 2.7 */
protected final static SimpleType CORE_TYPE_ENUM = new SimpleType(CLS_ENUM);
Cache Class because it is nominally parametric, but has no really useful information.
Since:2.7
/** * Cache {@link Class} because it is nominally parametric, but has no really * useful information. * * @since 2.7 */
protected final static SimpleType CORE_TYPE_CLASS = new SimpleType(CLS_CLASS);
Cache JsonNode because it is no critical path of simple tree model reading and does not have things to override
Since:2.10
/** * Cache {@link JsonNode} because it is no critical path of simple tree model * reading and does not have things to override * * @since 2.10 */
protected final static SimpleType CORE_TYPE_JSON_NODE = new SimpleType(CLS_JSON_NODE);
Since type resolution can be expensive (specifically when resolving actual generic types), we will use small cache to avoid repetitive resolution of core types
/** * Since type resolution can be expensive (specifically when resolving * actual generic types), we will use small cache to avoid repetitive * resolution of core types */
protected final LRUMap<Object,JavaType> _typeCache; /* /********************************************************** /* Configuration /********************************************************** */
Registered TypeModifiers: objects that can change details of JavaType instances factory constructs.
/** * Registered {@link TypeModifier}s: objects that can change details * of {@link JavaType} instances factory constructs. */
protected final TypeModifier[] _modifiers; protected final TypeParser _parser;
ClassLoader used by this factory [databind#624].
/** * ClassLoader used by this factory [databind#624]. */
protected final ClassLoader _classLoader; /* /********************************************************** /* Life-cycle /********************************************************** */ private TypeFactory() { this(null); }
Since:2.8
/** * @since 2.8 */
protected TypeFactory(LRUMap<Object,JavaType> typeCache) { if (typeCache == null) { typeCache = new LRUMap<Object,JavaType>(16, 200); } _typeCache = typeCache; _parser = new TypeParser(this); _modifiers = null; _classLoader = null; } protected TypeFactory(LRUMap<Object,JavaType> typeCache, TypeParser p, TypeModifier[] mods, ClassLoader classLoader) { if (typeCache == null) { typeCache = new LRUMap<Object,JavaType>(16, 200); } _typeCache = typeCache; // As per [databind#894] must ensure we have back-linkage from TypeFactory: _parser = p.withFactory(this); _modifiers = mods; _classLoader = classLoader; }
"Mutant factory" method which will construct a new instance with specified TypeModifier added as the first modifier to call (in case there are multiple registered).
/** * "Mutant factory" method which will construct a new instance with specified * {@link TypeModifier} added as the first modifier to call (in case there * are multiple registered). */
public TypeFactory withModifier(TypeModifier mod) { LRUMap<Object,JavaType> typeCache = _typeCache; TypeModifier[] mods; if (mod == null) { // mostly for unit tests mods = null; // 30-Jun-2016, tatu: for some reason expected semantics are to clear cache // in this case; can't recall why, but keeping the same typeCache = null; } else if (_modifiers == null) { mods = new TypeModifier[] { mod }; // 29-Jul-2019, tatu: Actually I think we better clear cache in this case // as well to ensure no leakage occurs (see [databind#2395]) typeCache = null; } else { // but may keep existing cache otherwise mods = ArrayBuilders.insertInListNoDup(_modifiers, mod); } return new TypeFactory(typeCache, _parser, mods, _classLoader); }
"Mutant factory" method which will construct a new instance with specified ClassLoader to use by findClass.
/** * "Mutant factory" method which will construct a new instance with specified * {@link ClassLoader} to use by {@link #findClass}. */
public TypeFactory withClassLoader(ClassLoader classLoader) { return new TypeFactory(_typeCache, _parser, _modifiers, classLoader); }
Mutant factory method that will construct new TypeFactory with identical settings except for different cache; most likely one with bigger maximum size.
Since:2.8
/** * Mutant factory method that will construct new {@link TypeFactory} with * identical settings except for different cache; most likely one with * bigger maximum size. * * @since 2.8 */
public TypeFactory withCache(LRUMap<Object,JavaType> cache) { return new TypeFactory(cache, _parser, _modifiers, _classLoader); }
Method used to access the globally shared instance, which has no custom configuration. Used by ObjectMapper to get the default factory when constructed.
/** * Method used to access the globally shared instance, which has * no custom configuration. Used by <code>ObjectMapper</code> to * get the default factory when constructed. */
public static TypeFactory defaultInstance() { return instance; }
Method that will clear up any cached type definitions that may be cached by this TypeFactory instance. This method should not be commonly used, that is, only use it if you know there is a problem with retention of type definitions; the most likely (and currently only known) problem is retention of Class instances via JavaType reference.
Since:2.4.1
/** * Method that will clear up any cached type definitions that may * be cached by this {@link TypeFactory} instance. * This method should not be commonly used, that is, only use it * if you know there is a problem with retention of type definitions; * the most likely (and currently only known) problem is retention * of {@link Class} instances via {@link JavaType} reference. * * @since 2.4.1 */
public void clearCache() { _typeCache.clear(); } public ClassLoader getClassLoader() { return _classLoader; } /* /********************************************************** /* Static methods for non-instance-specific functionality /********************************************************** */
Method for constructing a marker type that indicates missing generic type information, which is handled same as simple type for java.lang.Object.
/** * Method for constructing a marker type that indicates missing generic * type information, which is handled same as simple type for * <code>java.lang.Object</code>. */
public static JavaType unknownType() { return defaultInstance()._unknownType(); }
Static helper method that can be called to figure out type-erased call for given JDK type. It can be called statically since type resolution process can never change actual type-erased class; thereby static default instance is used for determination.
/** * Static helper method that can be called to figure out type-erased * call for given JDK type. It can be called statically since type resolution * process can never change actual type-erased class; thereby static * default instance is used for determination. */
public static Class<?> rawClass(Type t) { if (t instanceof Class<?>) { return (Class<?>) t; } // Should be able to optimize bit more in future... return defaultInstance().constructType(t).getRawClass(); } /* /********************************************************** /* Low-level helper methods /********************************************************** */
Low-level lookup method moved from ClassUtil, to allow for overriding of lookup functionality in environments like OSGi.
Since:2.6
/** * Low-level lookup method moved from {@link com.fasterxml.jackson.databind.util.ClassUtil}, * to allow for overriding of lookup functionality in environments like OSGi. * * @since 2.6 */
public Class<?> findClass(String className) throws ClassNotFoundException { if (className.indexOf('.') < 0) { Class<?> prim = _findPrimitive(className); if (prim != null) { return prim; } } // Two-phase lookup: first using context ClassLoader; then default Throwable prob = null; ClassLoader loader = this.getClassLoader(); if (loader == null) { loader = Thread.currentThread().getContextClassLoader(); } if (loader != null) { try { return classForName(className, true, loader); } catch (Exception e) { prob = ClassUtil.getRootCause(e); } } try { return classForName(className); } catch (Exception e) { if (prob == null) { prob = ClassUtil.getRootCause(e); } } ClassUtil.throwIfRTE(prob); throw new ClassNotFoundException(prob.getMessage(), prob); } protected Class<?> classForName(String name, boolean initialize, ClassLoader loader) throws ClassNotFoundException { return Class.forName(name, true, loader); } protected Class<?> classForName(String name) throws ClassNotFoundException { return Class.forName(name); } protected Class<?> _findPrimitive(String className) { if ("int".equals(className)) return Integer.TYPE; if ("long".equals(className)) return Long.TYPE; if ("float".equals(className)) return Float.TYPE; if ("double".equals(className)) return Double.TYPE; if ("boolean".equals(className)) return Boolean.TYPE; if ("byte".equals(className)) return Byte.TYPE; if ("char".equals(className)) return Character.TYPE; if ("short".equals(className)) return Short.TYPE; if ("void".equals(className)) return Void.TYPE; return null; } /* /********************************************************** /* Type conversion, parameterization resolution methods /********************************************************** */
Factory method for creating a subtype of given base type, as defined by specified subclass; but retaining generic type information if any. Can be used, for example, to get equivalent of "HashMap<String,Integer>" from "Map<String,Integer>" by giving HashMap.class as subclass. Short-cut for:
constructSpecializedType(baseType, subclass, class);
that is, will use "strict" compatibility checking, usually used for deserialization purposes (but often not for serialization).
/** * Factory method for creating a subtype of given base type, as defined * by specified subclass; but retaining generic type information if any. * Can be used, for example, to get equivalent of "HashMap&lt;String,Integer&gt;" * from "Map&lt;String,Integer&gt;" by giving <code>HashMap.class</code> * as subclass. * Short-cut for: *<pre> * constructSpecializedType(baseType, subclass, class); *</pre> * that is, will use "strict" compatibility checking, usually used for * deserialization purposes (but often not for serialization). */
public JavaType constructSpecializedType(JavaType baseType, Class<?> subclass) throws IllegalArgumentException { return constructSpecializedType(baseType, subclass, false); }
Factory method for creating a subtype of given base type, as defined by specified subclass; but retaining generic type information if any. Can be used, for example, to get equivalent of "HashMap<String,Integer>" from "Map<String,Integer>" by giving HashMap.class as subclass.
Params:
  • baseType – Declared base type with resolved type parameters
  • subclass – Runtime subtype to use for resolving
  • relaxedCompatibilityCheck – Whether checking for type-assignment compatibility should be "relaxed" (true) or "strict" (false): typically serialization uses relaxed, deserialization strict checking.
Returns:Resolved sub-type
Since:2.11
/** * Factory method for creating a subtype of given base type, as defined * by specified subclass; but retaining generic type information if any. * Can be used, for example, to get equivalent of "HashMap&lt;String,Integer&gt;" * from "Map&lt;String,Integer&gt;" by giving <code>HashMap.class</code> * as subclass. * * @param baseType Declared base type with resolved type parameters * @param subclass Runtime subtype to use for resolving * @param relaxedCompatibilityCheck Whether checking for type-assignment compatibility * should be "relaxed" ({@code true}) or "strict" ({@code false}): typically * serialization uses relaxed, deserialization strict checking. * * @return Resolved sub-type * * @since 2.11 */
public JavaType constructSpecializedType(JavaType baseType, Class<?> subclass, boolean relaxedCompatibilityCheck) throws IllegalArgumentException { // simple optimization to avoid costly introspection if type-erased type does NOT differ final Class<?> rawBase = baseType.getRawClass(); if (rawBase == subclass) { return baseType; } JavaType newType; // also: if we start from untyped, not much to save do { // bogus loop to be able to break if (rawBase == Object.class) { newType = _fromClass(null, subclass, EMPTY_BINDINGS); break; } if (!rawBase.isAssignableFrom(subclass)) { throw new IllegalArgumentException(String.format("Class %s not subtype of %s", ClassUtil.nameOf(subclass), ClassUtil.getTypeDescription(baseType) )); } // A few special cases where we can simplify handling: // (1) A small set of "well-known" List/Map subtypes where can take a short-cut if (baseType.isContainerType()) { if (baseType.isMapLikeType()) { if ((subclass == HashMap.class) || (subclass == LinkedHashMap.class) || (subclass == EnumMap.class) || (subclass == TreeMap.class)) { newType = _fromClass(null, subclass, TypeBindings.create(subclass, baseType.getKeyType(), baseType.getContentType())); break; } } else if (baseType.isCollectionLikeType()) { if ((subclass == ArrayList.class) || (subclass == LinkedList.class) || (subclass == HashSet.class) || (subclass == TreeSet.class)) { newType = _fromClass(null, subclass, TypeBindings.create(subclass, baseType.getContentType())); break; } // 29-Oct-2015, tatu: One further shortcut: there are variants of `EnumSet`, // but they are impl details and we basically do not care... if (rawBase == EnumSet.class) { return baseType; } } } // (2) Original target type has no generics -- just resolve subtype if (baseType.getBindings().isEmpty()) { newType = _fromClass(null, subclass, EMPTY_BINDINGS); break; } // (3) Sub-class does not take type parameters -- just resolve subtype int typeParamCount = subclass.getTypeParameters().length; if (typeParamCount == 0) { newType = _fromClass(null, subclass, EMPTY_BINDINGS); break; } // (4) If all else fails, do the full traversal using placeholders TypeBindings tb = _bindingsForSubtype(baseType, typeParamCount, subclass, relaxedCompatibilityCheck); newType = _fromClass(null, subclass, tb); } while (false); // 25-Sep-2016, tatu: As per [databind#1384] also need to ensure handlers get // copied as well newType = newType.withHandlersFrom(baseType); return newType; } private TypeBindings _bindingsForSubtype(JavaType baseType, int typeParamCount, Class<?> subclass, boolean relaxedCompatibilityCheck) { PlaceholderForType[] placeholders = new PlaceholderForType[typeParamCount]; for (int i = 0; i < typeParamCount; ++i) { placeholders[i] = new PlaceholderForType(i); } TypeBindings b = TypeBindings.create(subclass, placeholders); // First: pseudo-resolve to get placeholders in place: JavaType tmpSub = _fromClass(null, subclass, b); // Then find super-type JavaType baseWithPlaceholders = tmpSub.findSuperType(baseType.getRawClass()); if (baseWithPlaceholders == null) { // should be found but... throw new IllegalArgumentException(String.format( "Internal error: unable to locate supertype (%s) from resolved subtype %s", baseType.getRawClass().getName(), subclass.getName())); } // and traverse type hierarchies to both verify and to resolve placeholders String error = _resolveTypePlaceholders(baseType, baseWithPlaceholders); if (error != null) { // 28-Mar-2020, tatu: As per [databind#2632], need to ignore the issue in // some cases. For now, just fully ignore; may need to refine in future if (!relaxedCompatibilityCheck) { throw new IllegalArgumentException("Failed to specialize base type "+baseType.toCanonical()+" as " +subclass.getName()+", problem: "+error); } } final JavaType[] typeParams = new JavaType[typeParamCount]; for (int i = 0; i < typeParamCount; ++i) { JavaType t = placeholders[i].actualType(); // 18-Oct-2017, tatu: Looks like sometimes we have incomplete bindings (even if not // common, it is possible if subtype is type-erased class with added type // variable -- see test(s) with "bogus" type(s)). if (t == null) { t = unknownType(); } typeParams[i] = t; } return TypeBindings.create(subclass, typeParams); } private String _resolveTypePlaceholders(JavaType sourceType, JavaType actualType) throws IllegalArgumentException { List<JavaType> expectedTypes = sourceType.getBindings().getTypeParameters(); List<JavaType> actualTypes = actualType.getBindings().getTypeParameters(); final int actCount = actualTypes.size(); for (int i = 0, expCount = expectedTypes.size(); i < expCount; ++i) { JavaType exp = expectedTypes.get(i); JavaType act = (i < actCount) ? actualTypes.get(i) : unknownType(); if (!_verifyAndResolvePlaceholders(exp, act)) { // 14-May-2018, tatu: As per [databind#2034] it seems we better relax assignment // rules further -- at least likely "raw" (untyped, non-generic) base should probably // allow specialization. if (exp.hasRawClass(Object.class)) { continue; } // 19-Apr-2018, tatu: Hack for [databind#1964] -- allow type demotion // for `java.util.Map` key type if (and only if) target type is // `java.lang.Object` // 19-Aug-2019, tatu: Further, allow for all Map-like types, with assumption // first argument would be key; initially just because Scala Maps have // some issues (see [databind#2422]) if (i == 0) { if (sourceType.isMapLikeType() && act.hasRawClass(Object.class)) { continue; } } // 19-Nov-2018, tatu: To solve [databind#2155], let's allow type-compatible // assignment for interfaces at least... if (exp.isInterface()) { if (exp.isTypeOrSuperTypeOf(act.getRawClass())) { continue; } } return String.format("Type parameter #%d/%d differs; can not specialize %s with %s", (i+1), expCount, exp.toCanonical(), act.toCanonical()); } } return null; } private boolean _verifyAndResolvePlaceholders(JavaType exp, JavaType act) { // See if we have an actual type placeholder to resolve; if yes, replace if (act instanceof PlaceholderForType) { ((PlaceholderForType) act).actualType(exp); return true; } // if not, try to verify compatibility. But note that we can not // use simple equality as we need to resolve recursively if (exp.getRawClass() != act.getRawClass()) { return false; } // But we can check type parameters "blindly" List<JavaType> expectedTypes = exp.getBindings().getTypeParameters(); List<JavaType> 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 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.
Params:
  • superClass –
Since:2.7
/** * 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 <code>superClass</code>, 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 JavaType out of its canonical representation (see ResolvedType.toCanonical()).
Params:
  • 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
/** * 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.
Params:
  • type – Sub-type (leaf type) that implements expType
/** * 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 <code>expType</code> */
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 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 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.
Params:
  • type1 – Primary type to consider
  • type2 – Secondary type to consider
Since:2.2
/** * 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 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 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 = EMPTY_BINDINGS; } 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 ArrayType.

NOTE: type modifiers are NOT called on array type itself; but are called for element type (and other contained types)

/** * Method for constructing an {@link ArrayType}. *<p> * 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 ArrayType.

NOTE: type modifiers are NOT called on array type itself; but are called for contained types.

/** * Method for constructing an {@link ArrayType}. *<p> * 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 CollectionType.

NOTE: type modifiers are NOT called on Collection type itself; but are called for contained types.

/** * Method for constructing a {@link CollectionType}. *<p> * 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 CollectionType.

NOTE: type modifiers are NOT called on Collection type itself; but are called for contained types.

/** * Method for constructing a {@link CollectionType}. *<p> * 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) { TypeBindings bindings = TypeBindings.createIfNeeded(collectionClass, elementType); CollectionType result = (CollectionType) _fromClass(null, collectionClass, bindings); // 17-May-2017, tatu: As per [databind#1415], we better verify bound values if (but only if) // type being resolved was non-generic (i.e.element type was ignored) if (bindings.isEmpty() && (elementType != null)) { JavaType t = result.findSuperType(Collection.class); JavaType realET = t.getContentType(); if (!realET.equals(elementType)) { throw new IllegalArgumentException(String.format( "Non-generic Collection class %s did not resolve to something with element type %s but %s ", ClassUtil.nameOf(collectionClass), elementType, realET)); } } return result; }
Method for constructing a CollectionLikeType.

NOTE: type modifiers are NOT called on constructed type itself; but are called for contained types.

/** * Method for constructing a {@link CollectionLikeType}. *<p> * 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 CollectionLikeType.

NOTE: type modifiers are NOT called on constructed type itself; but are called for contained types.

/** * Method for constructing a {@link CollectionLikeType}. *<p> * 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 MapType instance

NOTE: type modifiers are NOT called on constructed type itself; but are called for contained types.

/** * Method for constructing a {@link MapType} instance *<p> * 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 MapType instance

NOTE: type modifiers are NOT called on constructed type itself; but are called for contained types.

/** * Method for constructing a {@link MapType} instance *<p> * 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) { TypeBindings bindings = TypeBindings.createIfNeeded(mapClass, new JavaType[] { keyType, valueType }); MapType result = (MapType) _fromClass(null, mapClass, bindings); // 17-May-2017, tatu: As per [databind#1415], we better verify bound values if (but only if) // type being resolved was non-generic (i.e.element type was ignored) if (bindings.isEmpty()) { JavaType t = result.findSuperType(Map.class); JavaType realKT = t.getKeyType(); if (!realKT.equals(keyType)) { throw new IllegalArgumentException(String.format( "Non-generic Map class %s did not resolve to something with key type %s but %s ", ClassUtil.nameOf(mapClass), keyType, realKT)); } JavaType realVT = t.getContentType(); if (!realVT.equals(valueType)) { throw new IllegalArgumentException(String.format( "Non-generic Map class %s did not resolve to something with value type %s but %s ", ClassUtil.nameOf(mapClass), valueType, realVT)); } } return result; }
Method for constructing a MapLikeType instance

NOTE: type modifiers are NOT called on constructed type itself; but are called for contained types.

/** * Method for constructing a {@link MapLikeType} instance *<p> * 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 MapLikeType instance

NOTE: type modifiers are NOT called on constructed type itself; but are called for contained types.

/** * Method for constructing a {@link MapLikeType} instance *<p> * 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.

/** * Method for constructing a type instance with specified parameterization. *<p> * 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
/** * 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
/** * @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 CollectionType) but also that most of supertype information is not gathered. This means that unless called on primitive types or String, results are probably not what you want to use.

Deprecated:Since 2.8, to indicate users should never call this method.
/** * Method that use by core Databind functionality, and that should NOT be called * by application code outside databind package. *<p> * 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 JavaType that represents a parameterized type. For example, to represent type List<Set<Integer>>, you could call
 JavaType inner = TypeFactory.constructParametricType(Set.class, Set.class, Integer.class);
 return TypeFactory.constructParametricType(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.constructParametricType(ArrayList.class, List.class, Integer.class);
since parameterization is applied to List. In most cases distinction does not matter, but there are types where it does; one such example is parameterization of types that implement Iterator.

NOTE: type modifiers are NOT called on constructed type.

Params:
  • parametrized – Actual full type
  • parameterClasses – Type parameters to apply
Since:2.5 NOTE: was briefly deprecated for 2.6
/** * Factory method for constructing {@link JavaType} that * represents a parameterized type. For example, to represent * type {@code List<Set<Integer>>}, you could * call *<pre> * JavaType inner = TypeFactory.constructParametricType(Set.class, Set.class, Integer.class); * return TypeFactory.constructParametricType(ArrayList.class, List.class, inner); *</pre> *<p> * 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 {@code ArrayList<Integer>}, the usual call would be: *<pre> * TypeFactory.constructParametricType(ArrayList.class, List.class, Integer.class); *</pre> * 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}. *<p> * 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 JavaType that represents a parameterized type. For example, to represent type List<Set<Integer>>, you could
 JavaType inner = TypeFactory.constructParametricType(Set.class, Set.class, Integer.class);
 return TypeFactory.constructParametricType(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.constructParametricType(ArrayList.class, List.class, Integer.class);
since parameterization is applied to List. In most cases distinction does not matter, but there are types where it does; one such example is parameterization of types that implement Iterator.

NOTE: type modifiers are NOT called on constructed type.

Params:
  • rawType – Actual type-erased type
  • parameterTypes – Type parameters to apply
Since:2.5 NOTE: was briefly deprecated for 2.6
/** * Factory method for constructing {@link JavaType} that * represents a parameterized type. For example, to represent * type {@code List<Set<Integer>>}, you could *<pre> * JavaType inner = TypeFactory.constructParametricType(Set.class, Set.class, Integer.class); * return TypeFactory.constructParametricType(ArrayList.class, List.class, inner); *</pre> *<p> * 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 {@code ArrayList<Integer>}, the usual call would be: *<pre> * TypeFactory.constructParametricType(ArrayList.class, List.class, Integer.class); *</pre> * 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}. *<p> * 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)
Deprecated:since 2.9 Use constructParametricType(Class<?>, JavaType...) instead
/** * @since 2.5 -- but will probably deprecated in 2.7 or 2.8 (not needed with 2.7) * * @deprecated since 2.9 Use {@link #constructParametricType(Class,JavaType...)} instead */
@Deprecated 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)
Deprecated:since 2.9 Use constructParametricType(Class<?>, Class<?>...) instead
/** * @since 2.5 -- but will probably deprecated in 2.7 or 2.8 (not needed with 2.7) * * @deprecated since 2.9 Use {@link #constructParametricType(Class,Class...)} instead */
@Deprecated 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.

/** * Method that can be used to construct "raw" Collection type; meaning that its * parameterization is unknown. * This is similar to using <code>Object.class</code> parameterization, * and is equivalent to calling: *<pre> * typeFactory.constructCollectionType(collectionClass, typeFactory.unknownType()); *</pre> *<p> * 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.

/** * Method that can be used to construct "raw" Collection-like type; meaning that its * parameterization is unknown. * This is similar to using <code>Object.class</code> parameterization, * and is equivalent to calling: *<pre> * typeFactory.constructCollectionLikeType(collectionClass, typeFactory.unknownType()); *</pre> *<p> * 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.

/** * Method that can be used to construct "raw" Map type; meaning that its * parameterization is unknown. * This is similar to using <code>Object.class</code> parameterization, * and is equivalent to calling: *<pre> * typeFactory.constructMapType(collectionClass, typeFactory.unknownType(), typeFactory.unknownType()); *</pre> *<p> * 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.

/** * Method that can be used to construct "raw" Map-like type; meaning that its * parameterization is unknown. * This is similar to using <code>Object.class</code> parameterization, * and is equivalent to calling: *<pre> * typeFactory.constructMapLikeType(collectionClass, typeFactory.unknownType(), typeFactory.unknownType()); *</pre> *<p> * 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<JavaType> 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()+": cannot determine type parameters"); } } return MapType.construct(rawClass, bindings, superClass, superInterfaces, kt, vt); } private JavaType _collectionType(Class<?> rawClass, TypeBindings bindings, JavaType superClass, JavaType[] superInterfaces) { List<JavaType> 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()+": cannot determine type parameters"); } return CollectionType.construct(rawClass, bindings, superClass, superInterfaces, ct); } private JavaType _referenceType(Class<?> rawClass, TypeBindings bindings, JavaType superClass, JavaType[] superInterfaces) { List<JavaType> 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()+": cannot determine type parameters"); } return ReferenceType.construct(rawClass, bindings, superClass, superInterfaces, ct); }
Factory method to call when no special 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 _newSimpleType
Since:2.7
/** * 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 SimpleType with no checks whatsoever. Default implementation calls the single argument constructor of SimpleType.
Since:2.7
/** * 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
/** * 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 if (clz == CLS_JSON_NODE) return CORE_TYPE_JSON_NODE; // since 2.10 } 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).
/** * Factory method that can be used if type information is passed * as Java typing returned from <code>getGenericXxx</code> 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; }
Params:
  • bindings – Mapping of formal parameter declarations (for generic types) into actual types
/** * @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 cannot 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 JavaType implementation.
/** * 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 = EMPTY_BINDINGS; } // 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.
/** * 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(); if (bindings == null) { throw new IllegalArgumentException("Null `bindings` passed (type variable \""+name+"\")"); } 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); final Type[] bounds; // 15-Jan-2019, tatu: As weird as this looks, apparently on some platforms (Arm CPU, mobile // devices), unsynchronized internal access can lead to issues, see: // // https://vmlens.com/articles/java-lang-reflect-typevariable-getbounds-is-not-thread-safe/ // // No good way to reproduce but since this should not be on critical path, let's add // syncing as it seems potentially necessary. synchronized (var) { 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); } }