美文网首页技术分享
TypeReference获取泛型参数

TypeReference获取泛型参数

作者: 十毛tenmao | 来源:发表于2019-12-07 22:45 被阅读0次

    使用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]);
    }
    

    延伸阅读:Java类型

    相关文章

      网友评论

        本文标题:TypeReference获取泛型参数

        本文链接:https://www.haomeiwen.com/subject/fvspgctx.html