随笔 - 394  文章 - 0  评论 - 946  阅读 - 143万 

由于项目使用的是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!!

posted on   程序诗人  阅读(21918)  评论(3编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
历史上的今天:
2012-08-09 WPF换肤之六:酷炫的时区浏览小精灵
2010-08-09 asp.net操作oracle存储过程的小问题
2010-08-09 C# Tostring() 格式大全 [转]
点击右上角即可分享
微信分享提示