由于项目使用的是 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!!
来源: https://www.cnblogs.com/scy251147/p/9451879.html