TypeReference获取泛型参数
2019-12-07 本文已影响0人
十毛tenmao
使用Gson、Jackson或Fastjson反序列化泛型时,需要传递泛型的真实类型,所以一般都通过集成
TypeReference
来实现。
获取泛型参数的实现方法
com.fasterxml.jackson.core.type.TypeReference
public abstract class TypeReference<T> implements Comparable<TypeReference<T>>
{
protected final Type _type;
protected TypeReference()
{
Type superClass = getClass().getGenericSuperclass();
if (superClass instanceof Class<?>) { // sanity check, should never happen
throw new IllegalArgumentException("Internal error: TypeReference constructed without actual type information");
}
/* 22-Dec-2008, tatu: Not sure if this case is safe -- I suspect
* it is possible to make it fail?
* But let's deal with specific
* case when we know an actual use case, and thereby suitable
* workarounds for valid case(s) and/or error to throw
* on invalid one(s).
*/
_type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
}
public Type getType() { return _type; }
/**
* The only reason we define this method (and require implementation
* of <code>Comparable</code>) is to prevent constructing a
* reference without type information.
*/
@Override
public int compareTo(TypeReference<T> o) { return 0; }
// just need an implementation, not a good one... hence ^^^
}
-
com.alibaba.fastjson.TypeReference
fastjson中的TypeReference基本原理类似
public class TypeReference<T> {
static ConcurrentMap<Type, Type> classTypeCache
= new ConcurrentHashMap<Type, Type>(16, 0.75f, 1);
protected final Type type;
/**
* Constructs a new type literal. Derives represented class from type
* parameter.
*
* <p>Clients create an empty anonymous subclass. Doing so embeds the type
* parameter in the anonymous class's type hierarchy so we can reconstitute it
* at runtime despite erasure.
*/
protected TypeReference(){
Type superClass = getClass().getGenericSuperclass();
Type type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
Type cachedType = classTypeCache.get(type);
if (cachedType == null) {
classTypeCache.putIfAbsent(type, type);
cachedType = classTypeCache.get(type);
}
this.type = cachedType;
}
/**
* @since 1.2.9
* @param actualTypeArguments
*/
protected TypeReference(Type... actualTypeArguments){
Class<?> thisClass = this.getClass();
Type superClass = thisClass.getGenericSuperclass();
ParameterizedType argType = (ParameterizedType) ((ParameterizedType) superClass).getActualTypeArguments()[0];
Type rawType = argType.getRawType();
Type[] argTypes = argType.getActualTypeArguments();
int actualIndex = 0;
for (int i = 0; i < argTypes.length; ++i) {
if (argTypes[i] instanceof TypeVariable &&
actualIndex < actualTypeArguments.length) {
argTypes[i] = actualTypeArguments[actualIndex++];
}
// fix for openjdk and android env
if (argTypes[i] instanceof GenericArrayType) {
argTypes[i] = TypeUtils.checkPrimitiveArray(
(GenericArrayType) argTypes[i]);
}
// 如果有多层泛型且该泛型已经注明实现的情况下,判断该泛型下一层是否还有泛型
if(argTypes[i] instanceof ParameterizedType) {
argTypes[i] = handlerParameterizedType((ParameterizedType) argTypes[i], actualTypeArguments, actualIndex);
}
}
Type key = new ParameterizedTypeImpl(argTypes, thisClass, rawType);
Type cachedType = classTypeCache.get(key);
if (cachedType == null) {
classTypeCache.putIfAbsent(key, key);
cachedType = classTypeCache.get(key);
}
type = cachedType;
}
private Type handlerParameterizedType(ParameterizedType type, Type[] actualTypeArguments, int actualIndex) {
Class<?> thisClass = this.getClass();
Type rawType = type.getRawType();
Type[] argTypes = type.getActualTypeArguments();
for(int i = 0; i < argTypes.length; ++i) {
if (argTypes[i] instanceof TypeVariable && actualIndex < actualTypeArguments.length) {
argTypes[i] = actualTypeArguments[actualIndex++];
}
// fix for openjdk and android env
if (argTypes[i] instanceof GenericArrayType) {
argTypes[i] = TypeUtils.checkPrimitiveArray(
(GenericArrayType) argTypes[i]);
}
// 如果有多层泛型且该泛型已经注明实现的情况下,判断该泛型下一层是否还有泛型
if(argTypes[i] instanceof ParameterizedType) {
return handlerParameterizedType((ParameterizedType) argTypes[i], actualTypeArguments, actualIndex);
}
}
Type key = new ParameterizedTypeImpl(argTypes, thisClass, rawType);
return key;
}
/**
* Gets underlying {@code Type} instance.
*/
public Type getType() {
return type;
}
public final static Type LIST_STRING = new TypeReference<List<String>>() {}.getType();
}
com.google.gson.reflect.TypeToken
gson中的TypeToken原理也是一样的
/**
* Returns the type from super class's type parameter in {@link $Gson$Types#canonicalize
* canonical form}.
*/
static Type getSuperclassTypeParameter(Class<?> subclass) {
Type superclass = subclass.getGenericSuperclass();
if (superclass instanceof Class) {
throw new RuntimeException("Missing type parameter.");
}
ParameterizedType parameterized = (ParameterizedType) superclass;
return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]);
}