基於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!!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM