zoukankan      html  css  js  c++  java
  • 基于FastJson的通用泛型解决方案

    由于项目使用的是fastjson,也无法换成其他的序列化框架,所以研究了一下他对泛型序列化和反序列化的支持能力,最终解决了这个问题。

    要达成的目标

    我的封装方式属于通用封装,我要达到的目标是如下的使用方式:

    放入数据:

     Map<String, OffheapDTO> mapxx = new HashMap<>();
            mapxx.put("1",new OffheapDTO().create());
            mapxx.put("2",new OffheapDTO().create());
            mapxx.put("3",new OffheapDTO().create());
            mapxx.put("4",new OffheapDTO().create());
            mapxx.put("5",new OffheapDTO().create());
            offheapCacheWrapper.putMap("maptest", mapxx);
    

    获取数据:

     Map<String, OffheapDTO> resultmap = offheapCacheWrapper.queryMap("cachemap")

    OffheapDTO对象的定义方式如下:

    class OffheapDTO implements Serializable, Comparable{
        private String name;
        private String address;
        private String mark;
        private int order;
       //省略getset
    }

    也就是我可以随意的把任何对象进行序列化操作,然后可以随意的把任何已经序列化的对象,反序列化回来。

    第一版代码代码,未中其意

     
    putMap方法代码如下:
        public <T> void putMap(String key, T value, long expireSeconds) {
            try {
                EntityWrapper<T> entityWrapper = new EntityWrapper<>().create(key, value, expireSeconds);
                initMapContainer(OffheapCacheConst.MAP_CONTAINER_FOR_STRING).put(key, JSON.toJSONString(entityWrapper));
            } catch (Exception ex) {
                logger.error(OffheapCacheConst.PACKAGE_CONTAINER + "putMapSingle with expires exception:", ex);
                throw ex;
            }
        }

    queryMap方法代码如下:

        public <T> T queryMap(String key) {
            try {
                Object result = initMapContainer(OffheapCacheConst.MAP_CONTAINER_FOR_STRING).get(key);
                if(result == null){
                    return null;
                }
                //反序列化出entityWrapper
                EntityWrapper entityWrapper = JSON.parseObject(result.toString());
                return (T)entityWrapper.getEntity();
            } catch (Exception ex) {
                logger.error(OffheapCacheConst.PACKAGE_CONTAINER + "queryMap exception:", ex);
                return null;
            }
        }
    

    结果当我反序列化的时候,调用resultmap.get("1")的时候,提示我无法将jsonObject转变成OffheapDTO. 调试进去发现,List对象里面装载的仍然是jsonObject数据。初次尝试失败。

    第二版代码,苦尽甘来

    之后翻看了百度,查阅了大量资料,然后看到了关于TypeReference的代码,之后将queryMap方法修改如下:

        public <T> T queryMap(String key) {
            try {
                Object result = initMapContainer(OffheapCacheConst.MAP_CONTAINER_FOR_STRING).get(key);
                if(result == null){
                    return null;
                }
                //反序列化出entityWrapper
                EntityWrapper entityWrapper = JSON.parseObject(result.toString(),new TypeReference<EntityWrapper<T>>() {});
                return (T)entityWrapper.getEntity();
            } catch (Exception ex) {
                logger.error(OffheapCacheConst.PACKAGE_CONTAINER + "queryMap exception:", ex);
                return null;
            }
        }
    

    注意代码中黄色部分。

    然后当我再次进行反序列化的时候,我发现resultMap.get(“1”)已经可以拿到正常的OffheapDTO对象了。心中一喜,然后运行resultMap.get(“1”).getName(), 居然又报错,提示无法将jsonObject转变成OffheapDTO对象,发现原来存储的字段,居然都是jsonObject类型。这次就有点慌了。

    第三版代码,蓦然回首

    不过想想fastjson这么成熟,定然有前人的轮子,所以就继续查阅资料,终于查到了setAutoTypeSupport这个属性,没想到一试,居然解决了问题。

    首先,程序启动的时候,需要开启这个属性,至于这个属性真正的意义,去翻阅fastjson文档,我这里就不赘述了:

          //开启fastjson autotype功能(不开启,造成EntityWrapper<T>中的T无法正常解析)
            ParserConfig.getGlobalInstance().setAutoTypeSupport(true);

    然后,在序列化的时候,需要附带上序列化的class名称(黄色标记部分):

        public <T> void putMap(String key, T value, long expireSeconds) {
            try {
                EntityWrapper<T> entityWrapper = new EntityWrapper<>().create(key, value, expireSeconds);
                initMapContainer(OffheapCacheConst.MAP_CONTAINER_FOR_STRING).put(key, JSON.toJSONString(entityWrapper, SerializerFeature.WriteClassName));
            } catch (Exception ex) {
                logger.error(OffheapCacheConst.PACKAGE_CONTAINER + "putMapSingle with expires exception:", ex);
                throw ex;
            }
        }

    最后,在反序列化的时候,利用TypeReference进行类型指定即可:

        public <T> T queryMap(String key) {
            try {
                Object result = initMapContainer(OffheapCacheConst.MAP_CONTAINER_FOR_STRING).get(key);
                if(result == null){
                    return null;
                }
                //反序列化出entityWrapper
                EntityWrapper entityWrapper = JSON.parseObject(result.toString(),new TypeReference<EntityWrapper<T>>() {});
                return (T)entityWrapper.getEntity();
            } catch (Exception ex) {
                logger.error(OffheapCacheConst.PACKAGE_CONTAINER + "queryMap exception:", ex);
                return null;
            }
        }
    

    这样,无论你的类有多复杂,都可以搞定,比如像下面这样的:

    Map<String,List< OffheapDTO>> resultmap = offheapCacheWrapper.queryMap("maptest");

    甚至这样的:

    List<Map<String,List<Set<OffheapDTO>>>> resultmap = offheapCacheWrapper.queryMap("maptest");

    Enjoy!!

  • 相关阅读:
    引用&符号详解
    简单计算器
    while循环输出的表格
    设置和获取变量类型
    位运算符
    MySQL基础(一)SQL基础
    python 21天网络爬虫使用 代理
    Spark入门(一)
    Apache spark2.1.0编译hadoop-2.6-cdh5.11.2的对应版本
    Java 多线程
  • 原文地址:https://www.cnblogs.com/scy251147/p/9451879.html
Copyright © 2011-2022 走看看