package com.fasterxml.jackson.jr.type;

import java.io.Serializable;
import java.lang.reflect.*;
import java.util.*;

import com.fasterxml.jackson.jr.ob.impl.ClassKey;

Object that is used for resolving generic type information of a class so that it is accessible using simple API. Resolved types are also starting point for accessing resolved (generics aware) return and argument types of class members (methods, fields, constructors).

Note that resolver instances are stateful in that resolvers cache resolved types for efficiency. Since this is internal state and not directly visible to callers, access to state is fully synchronized so that access from multiple threads is safe.

/** * Object that is used for resolving generic type information of a class * so that it is accessible using simple API. Resolved types are also starting * point for accessing resolved (generics aware) return and argument types * of class members (methods, fields, constructors). *<p> * Note that resolver instances are stateful in that resolvers cache resolved * types for efficiency. Since this is internal state and not directly visible * to callers, access to state is fully synchronized so that access from * multiple threads is safe. */
public class TypeResolver implements Serializable { private static final long serialVersionUID = 1L; private final static ResolvedType[] NO_TYPES = new ResolvedType[0]; // // Pre-created instances private final static ResolvedType TYPE_OBJECT = new ResolvedType(Object.class, /* no super-class*/ null, null, null); private final static HashMap<ClassKey, ResolvedType> _primitives; static { _primitives = new HashMap<ClassKey, ResolvedType>(16); ResolvedType[] all = new ResolvedType[] { new ResolvedType(Boolean.TYPE), new ResolvedType(Byte.TYPE), new ResolvedType(Short.TYPE), new ResolvedType(Character.TYPE), new ResolvedType(Integer.TYPE), new ResolvedType(Long.TYPE), new ResolvedType(Float.TYPE), new ResolvedType(Double.TYPE) }; for (ResolvedType type : all) { _primitives.put(new ClassKey(type.erasedType(), 0), type); } _primitives.put(new ClassKey(Void.TYPE, 0), new ResolvedType(Void.TYPE)); _primitives.put(new ClassKey(Object.class, 0), TYPE_OBJECT); } // // Caching protected final transient Map<ClassKey,ResolvedType> _cache = new HashMap<ClassKey,ResolvedType>(16, 0.8f); public TypeResolver() { } // To make sure we have empty but valid TypeResolver do this: protected Object readResolve() { if (_cache == null) { return new TypeResolver(); } return this; }
Factory method for resolving specified Java Type, given TypeBindings needed to resolve any type variables.

Use of this method is discouraged (use if and only if you really know what you are doing!); but if used, type bindings passed should come from ResolvedType instance of declaring class (or interface).

/** * Factory method for resolving specified Java {@link java.lang.reflect.Type}, given * {@link TypeBindings} needed to resolve any type variables. *<p> * Use of this method is discouraged (use if and only if you really know what you * are doing!); but if used, type bindings passed should come from {@link ResolvedType} * instance of declaring class (or interface). */
public ResolvedType resolve(TypeBindings typeBindings, Type jdkType) { return _fromAny(null, jdkType, typeBindings); } private ResolvedType _fromAny(ClassStack context, Type mainType, TypeBindings typeBindings) { if (mainType instanceof Class<?>) { return _fromClass(context, (Class<?>) mainType, typeBindings); } if (mainType instanceof ResolvedType) { return (ResolvedType) mainType; } if (mainType instanceof ParameterizedType) { return _fromParamType(context, (ParameterizedType) mainType, typeBindings); } if (mainType instanceof GenericArrayType) { ResolvedType elementType = _fromAny(context, ((GenericArrayType) mainType).getGenericComponentType(), typeBindings); // Figuring out raw class for generic array is actually bit tricky... Object emptyArray = Array.newInstance(elementType.erasedType(), 0); return new ResolvedType(emptyArray.getClass(), typeBindings, elementType); } if (mainType instanceof TypeVariable<?>) { return _fromVariable(context, (TypeVariable<?>) mainType, typeBindings); } if (mainType instanceof WildcardType) { return _fromAny(context, ((WildcardType) mainType).getUpperBounds()[0], typeBindings); } // should never get here... throw new IllegalArgumentException("Unrecognized type class: "+mainType.getClass().getName()); } private ResolvedType _fromClass(ClassStack context, Class<?> rawType, TypeBindings typeBindings) { final ClassKey key = new ClassKey(rawType, 0); if (rawType.isPrimitive()) { ResolvedType type = _primitives.get(key); if (type != null) { return type; } } if (context == null) { context = new ClassStack(rawType); } else { ClassStack prev = context.find(rawType); if (prev != null) { // Self-reference: needs special handling, then... RecursiveType selfRef = new RecursiveType(rawType, typeBindings); prev.addSelfReference(selfRef); return selfRef; } // no, can just add context = context.child(rawType); } ResolvedType type; if (typeBindings.isEmpty()) { synchronized (_cache) { type = _cache.get(key); if (type != null) { return type; } } type = _constructType(context, rawType, typeBindings); synchronized (_cache) { if (_cache.size() >= 100) { // so hash table max 128 entries _cache.clear(); } _cache.put(key, type); } } else { type = _constructType(context, rawType, typeBindings); } context.resolveSelfReferences(type); return type; } private ResolvedType _constructType(ClassStack context, Class<?> rawType, TypeBindings typeBindings) { // Ok: no easy shortcut, let's figure out type of type... if (rawType.isArray()) { ResolvedType elementType = _fromAny(context, rawType.getComponentType(), typeBindings); return new ResolvedType(rawType, typeBindings, elementType); } // For other types super interfaces are needed... if (rawType.isInterface()) { return new ResolvedType(rawType, typeBindings, _resolveSuperInterfaces(context, rawType, typeBindings)); } return new ResolvedType(rawType, _resolveSuperClass(context, rawType, typeBindings), typeBindings, _resolveSuperInterfaces(context, rawType, typeBindings)); } private ResolvedType[] _resolveSuperInterfaces(ClassStack context, Class<?> rawType, TypeBindings typeBindings) { Type[] types = rawType.getGenericInterfaces(); if (types == null || types.length == 0) { return NO_TYPES; } int len = types.length; ResolvedType[] resolved = new ResolvedType[len]; for (int i = 0; i < len; ++i) { resolved[i] = _fromAny(context, types[i], typeBindings); } return resolved; } private ResolvedType _resolveSuperClass(ClassStack context, Class<?> rawType, TypeBindings typeBindings) { Type parent = rawType.getGenericSuperclass(); if (parent == null) { return null; } return _fromAny(context, parent, typeBindings); } private ResolvedType _fromParamType(ClassStack context, ParameterizedType ptype, TypeBindings parentBindings) { Class<?> rawType = (Class<?>) ptype.getRawType(); Type[] params = ptype.getActualTypeArguments(); int len = params.length; ResolvedType[] types = new ResolvedType[len]; for (int i = 0; i < len; ++i) { types[i] = _fromAny(context, params[i], parentBindings); } TypeBindings newBindings = TypeBindings.create(rawType, types); return _fromClass(context, rawType, newBindings); } private ResolvedType _fromVariable(ClassStack context, TypeVariable<?> variable, TypeBindings typeBindings) { String name = variable.getName(); ResolvedType type = typeBindings.findBoundType(name); if (type != null) { return type; } if (typeBindings.hasUnbound(name)) { return TYPE_OBJECT; } typeBindings = typeBindings.withUnboundVariable(name); Type[] bounds = variable.getBounds(); return _fromAny(context, bounds[0], typeBindings); } }