美文网首页
Gson、Fastjson解析里的Type,如何用一个方法解析所

Gson、Fastjson解析里的Type,如何用一个方法解析所

作者: 蒸汽飞船 | 来源:发表于2017-11-28 17:19 被阅读132次

    使用Gson或者fastjson解析数据,我们的梦想是用一套方法解析所有数据:

    public<T> T parse(String jsonStr,Class<T> clazz)
    

    但这只能是想想,比如上面的方法,list类型就没法处理了

    解析object和list,肯定得分开俩方法写,想用一个方法的话就得手动传Type。Gson和fastjson之类都有生成Type的辅助类TypeToken 和TypeReference。

    TypeToken 和TypeReference都是辅助生成Type的工具类(大概是这样,没仔细研究过),其实这个是可以自己写方法实现的,目标是一个方法来解析所有的数据。参考鸿祥大神的一部分代码和抄袭Gson的部分源码,抽出一个生成Type的类,支持object和list,代码不多两三百行,源码其实我也不懂,只是根据需要抽出来的,

    1.获取Type使用如下:

    //普通object
    Type type = new ParseType<User>() {}.getType();
    //列表list
    Type type = new ParseType<List<User>>() {}.getType();
    //复杂的
    Type type = new ParseType<NetReslult<List<User>>>() {}.getType();
    
    //解析
    User user =  JSON.parseObject(jsonString,type);  //fastjson
    User user = gson.fromJson(jsonString, type);        //gson
    
    NetReslult<List<User>> netResult = JSON.parseObject(jsonString, type);
    NetReslult<List<User>> netResult = gson.fromJson(jsonString, type);
    
    ps:注意new出来的是ParseType之类的对象 new ParseType<T>() {},通过泛型这种方式来获取Type类型必须用子类的对象,看清楚了,所有new的ParseType后面都有{}所以生成的是子类的对象。

    2.ParseType源码:

    public class ParseType<T> {
    
    
        public Type mType;
    
        public ParseType() {
            mType = getSuperclassTypeParameter(getClass());
        }
    
    
        public Type getType() {
            return mType;
        }
    
        static Type getSuperclassTypeParameter(Class<?> subclass) {
            Type superclass = subclass.getGenericSuperclass();
            if (superclass instanceof Class) {
                throw new RuntimeException("Missing type parameter.");
            }
            ParameterizedType parameterized = (ParameterizedType) superclass;
            return canonicalize(parameterized.getActualTypeArguments()[0]);
        }
    
    
        static Type canonicalize(Type type) {
            if (type instanceof Class) {
                Class<?> c = (Class<?>) type;
                return c.isArray() ? new GenericArrayTypeImpl(canonicalize(c.getComponentType())) : c;
    
            } else if (type instanceof ParameterizedType) {
                ParameterizedType p = (ParameterizedType) type;
                return new ParameterizedTypeImpl(p.getOwnerType(),
                        p.getRawType(), p.getActualTypeArguments());
    
            } else if (type instanceof GenericArrayType) {
                GenericArrayType g = (GenericArrayType) type;
                return new GenericArrayTypeImpl(g.getGenericComponentType());
    
            } else if (type instanceof WildcardType) {
                WildcardType w = (WildcardType) type;
                return new WildcardTypeImpl(w.getUpperBounds(), w.getLowerBounds());
    
            } else {
                // type is either serializable as-is or unsupported
                return type;
            }
        }
    
    
        private static final class GenericArrayTypeImpl implements GenericArrayType, Serializable {
            private final Type componentType;
    
            public GenericArrayTypeImpl(Type componentType) {
                this.componentType = canonicalize(componentType);
            }
    
            public Type getGenericComponentType() {
                return componentType;
            }
    
            @Override public boolean equals(Object o) {
                return o instanceof GenericArrayType
                        && $equals(this, (GenericArrayType) o);
            }
    
            @Override public int hashCode() {
                return componentType.hashCode();
            }
    
            @Override public String toString() {
                return typeToString(componentType) + "[]";
            }
    
            private static final long serialVersionUID = 0;
        }
    
    
        private static final class ParameterizedTypeImpl implements ParameterizedType, Serializable {
            private final Type ownerType;
            private final Type rawType;
            private final Type[] typeArguments;
    
            public ParameterizedTypeImpl(Type ownerType, Type rawType, Type... typeArguments) {
                // require an owner type if the raw type needs it
                if (rawType instanceof Class<?>) {
                    Class<?> rawTypeAsClass = (Class<?>) rawType;
                    boolean isStaticOrTopLevelClass = Modifier.isStatic(rawTypeAsClass.getModifiers())
                            || rawTypeAsClass.getEnclosingClass() == null;
                    checkArgument(ownerType != null || isStaticOrTopLevelClass);
                }
    
                this.ownerType = ownerType == null ? null : canonicalize(ownerType);
                this.rawType = canonicalize(rawType);
                this.typeArguments = typeArguments.clone();
                for (int t = 0, length = this.typeArguments.length; t < length; t++) {
                    checkNotNull(this.typeArguments[t]);
                    checkNotPrimitive(this.typeArguments[t]);
                    this.typeArguments[t] = canonicalize(this.typeArguments[t]);
                }
            }
    
            public Type[] getActualTypeArguments() {
                return typeArguments.clone();
            }
    
            public Type getRawType() {
                return rawType;
            }
    
            public Type getOwnerType() {
                return ownerType;
            }
    
            @Override public boolean equals(Object other) {
                return other instanceof ParameterizedType
                        && $equals(this, (ParameterizedType) other);
            }
    
            @Override public int hashCode() {
                return Arrays.hashCode(typeArguments)
                        ^ rawType.hashCode()
                        ^ hashCodeOrZero(ownerType);
            }
    
            @Override public String toString() {
                int length = typeArguments.length;
                if (length == 0) {
                    return typeToString(rawType);
                }
    
                StringBuilder stringBuilder = new StringBuilder(30 * (length + 1));
                stringBuilder.append(typeToString(rawType)).append("<").append(typeToString(typeArguments[0]));
                for (int i = 1; i < length; i++) {
                    stringBuilder.append(", ").append(typeToString(typeArguments[i]));
                }
                return stringBuilder.append(">").toString();
            }
    
            private static final long serialVersionUID = 0;
        }
    
        private static final class WildcardTypeImpl implements WildcardType, Serializable {
    
            static final Type[] EMPTY_TYPE_ARRAY = new Type[] {};
    
            private final Type upperBound;
            private final Type lowerBound;
    
            public WildcardTypeImpl(Type[] upperBounds, Type[] lowerBounds) {
                checkArgument(lowerBounds.length <= 1);
                checkArgument(upperBounds.length == 1);
    
                if (lowerBounds.length == 1) {
                    checkNotNull(lowerBounds[0]);
                    checkNotPrimitive(lowerBounds[0]);
                    checkArgument(upperBounds[0] == Object.class);
                    this.lowerBound = canonicalize(lowerBounds[0]);
                    this.upperBound = Object.class;
    
                } else {
                    checkNotNull(upperBounds[0]);
                    checkNotPrimitive(upperBounds[0]);
                    this.lowerBound = null;
                    this.upperBound = canonicalize(upperBounds[0]);
                }
            }
    
            public Type[] getUpperBounds() {
                return new Type[] { upperBound };
            }
    
            public Type[] getLowerBounds() {
                return lowerBound != null ? new Type[] { lowerBound } : EMPTY_TYPE_ARRAY;
            }
    
            @Override public boolean equals(Object other) {
                return other instanceof WildcardType
                        && $equals(this, (WildcardType) other);
            }
    
            @Override public int hashCode() {
                // this equals Arrays.hashCode(getLowerBounds()) ^ Arrays.hashCode(getUpperBounds());
                return (lowerBound != null ? 31 + lowerBound.hashCode() : 1)
                        ^ (31 + upperBound.hashCode());
            }
    
            @Override public String toString() {
                if (lowerBound != null) {
                    return "? super " + typeToString(lowerBound);
                } else if (upperBound == Object.class) {
                    return "?";
                } else {
                    return "? extends " + typeToString(upperBound);
                }
            }
    
            private static final long serialVersionUID = 0;
        }
    
    
    
        public static <T> T checkNotNull(T obj) {
            if (obj == null) {
                throw new NullPointerException();
            }
            return obj;
        }
    
        public static void checkArgument(boolean condition) {
            if (!condition) {
                throw new IllegalArgumentException();
            }
        }
    
        public static String typeToString(Type type) {
            return type instanceof Class ? ((Class<?>) type).getName() : type.toString();
        }
    
        static int hashCodeOrZero(Object o) {
            return o != null ? o.hashCode() : 0;
        }
    
        static void checkNotPrimitive(Type type) {
            boolean conmdition = !(type instanceof Class<?>) || !((Class<?>) type).isPrimitive();
            if(!conmdition){
                throw new IllegalArgumentException();
            }
        }
    
    
        static boolean $equal(Object a, Object b) {
            return a == b || (a != null && a.equals(b));
        }
    
        public static boolean $equals(Type a, Type b) {
            if (a == b) {
                // also handles (a == null && b == null)
                return true;
    
            } else if (a instanceof Class) {
                // Class already specifies equals().
                return a.equals(b);
    
            } else if (a instanceof ParameterizedType) {
                if (!(b instanceof ParameterizedType)) {
                    return false;
                }
    
                // TODO: save a .clone() call
                ParameterizedType pa = (ParameterizedType) a;
                ParameterizedType pb = (ParameterizedType) b;
                return $equal(pa.getOwnerType(), pb.getOwnerType())
                        && pa.getRawType().equals(pb.getRawType())
                        && Arrays.equals(pa.getActualTypeArguments(), pb.getActualTypeArguments());
    
            } else if (a instanceof GenericArrayType) {
                if (!(b instanceof GenericArrayType)) {
                    return false;
                }
    
                GenericArrayType ga = (GenericArrayType) a;
                GenericArrayType gb = (GenericArrayType) b;
                return $equals(ga.getGenericComponentType(), gb.getGenericComponentType());
    
            } else if (a instanceof WildcardType) {
                if (!(b instanceof WildcardType)) {
                    return false;
                }
    
                WildcardType wa = (WildcardType) a;
                WildcardType wb = (WildcardType) b;
                return Arrays.equals(wa.getUpperBounds(), wb.getUpperBounds())
                        && Arrays.equals(wa.getLowerBounds(), wb.getLowerBounds());
    
            } else if (a instanceof TypeVariable) {
                if (!(b instanceof TypeVariable)) {
                    return false;
                }
                TypeVariable<?> va = (TypeVariable<?>) a;
                TypeVariable<?> vb = (TypeVariable<?>) b;
                return va.getGenericDeclaration() == vb.getGenericDeclaration()
                        && va.getName().equals(vb.getName());
    
            } else {
                // This isn't a type we support. Could be a generic array type, wildcard type, etc.
                return false;
            }
        }
    }
    

    3.说明

    其实就是实现了一个类似TypeToken或者TypeRefrence的东西。

    4.解析使用

    同步请求中使用:
    写一个请求类继承ParseType:

    public class SyncRequest<T> extends ParseType<T> {
    
        public T syncRequest(String url,Params  params) throws Exception{
            String jsonString = 网络请求代码略...;
            T parse = JSON.parseObject(jsonString,mType);
            return parse;
        }
    }
    

    请求+解析:

    User user = new SyncRequest<User>().syncRequest(url,params);
    NetReslult<List<User>> data =  new SyncRequest<NetReslult<List<User>>>(){}.syncRequest(url,params);
    

    看着像不像一个方法解析了所有数据。

    相关文章

      网友评论

          本文标题:Gson、Fastjson解析里的Type,如何用一个方法解析所

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