【Jackson】jackson map ClassCastException

考慮這個場景,我們在設計數據庫表時,往往會加一個擴展字段列,可以是varchar類型。程序中可以將各種擴展字段放入一個map結構中,再序列化爲string,存入數據庫。下面以json作爲序列化方式來看一個例子:

比如下面Data類中的ext字段:

public class Data {

    private long id;
    private String name;
    private Map<String, Object> ext;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Map<String, Object> getExt() {
        return ext;
    }

    public void setExt(Map<String, Object> ext) {
        this.ext = ext;
    }
}

下面通過程序往ext裏放入long類型的擴展字段:

        Data data = new Data();
        data.setId(1);
        data.setName("d1");
        Map<String, Object> ext = new HashMap<>();
        ext.put("duration", 128);

        data.setExt(ext);

        String json = mapper.writeValueAsString(data);
        System.out.println(json);

然後再讀出來:

        Data data = mapper.readValue(json, Data.class);
        long duration = (long) data.getExt().get("duration");
        System.out.println(duration);

這時會拋一個ClassCastException。

 

這是因爲我們設計的擴展字段是string,object類型的,所以反序列化時,map的key的實際類型由jackson自行推斷,因爲是數字,所以jackson會轉爲int,如果溢出則轉爲long,上面的case沒有溢出,所以實際類型是int。這時我們強轉爲long自然就報錯了。

存入一個long,讀到一個int???這確實是一個坑。。。

 

怎麼處理比較好?

首先要明確一點,如果反序列化爲Map<String, Object>,那麼key的實際類型是由jackson決定的,我們在強轉時一定要判斷實際類型。

對於上面的例子,我們可以用instanceOf先做判斷,然後轉爲number類處理:

        Data data = mapper.readValue(json, Data.class);
        Object duration = data.getExt().get("duration");
        if (duration instanceof Number) {
            long value = ((Number) duration).longValue();
        }

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章