關於Gson解析的使用匯總

xingstarx發表於2018-01-18

筆者前幾周在處理資料解析這塊碰到了好多的坑 這裡只討論資料解析這塊的知識

這裡並不打算直接通過object = new Gson().fromJson(json, object.getClass());得到對應的json的實體型別

而是通過JsonParser Api對資料進行解析,方便後面講到對於複雜特殊的json串進行解析

image.png
通過上圖的程式碼片段可以清晰的看到對於一個json串,使用JsonParser api解析後,它就是一個JsonElement物件了,但是這個JsonElement到底是什麼,對應的到底是哪一類呢,看了程式碼可以知道,總共就四類,JsonNull(空串這樣的),JsonObject,JsonArray,JsonPrimitive,相信接觸過json的同學對JsonObject,JsonArray很熟悉了吧,用的最多的就是這兩個,JsonNull用的少,JsonPrimitive估計都沒有聽過吧

JsonNull沒什麼好講的,自己做實驗就知道了,JsonPrimitive表示的是json串裡面的內容是基礎型別,可以看類的定義

image.png

當然了也存在特殊的情況,它也是JsonPrimitive型別

我們再看一段程式碼片段 定義了一個string變數

String json = "{\"code\":200, \"message\":\"ok\", \"data\":\"{\\\"id\\\":131,\\\"appId\\\":6,\\\"versionCode\\\":6014000}\"}";
複製程式碼

image.png
我們需要關注的是json串裡面key為“data”所對應的value,應該看得比較清楚,data的內容都帶有轉義符號,那麼我們該怎麼解析這樣的資料呢?

回答問題前,我們看看這段程式碼的執行結果,最終輸出的是

json == {"code":200, "message":"ok", "data":"{\"id\":131,\"appId\":6,\"versionCode\":6014000}"}
isJsonObject
isJsonPrimitive == true
複製程式碼

可以看到data的內容就是一個jsonPrimitive型別的,因為它在後端處理的時候,就將真實的內容給拍平了(不知道能不能用序列化描述額,總之是被轉義了,看起來就不是一個json串,而變成了一個純粹的string)

那麼在我們解析這個被轉義的字串的時候,需要把轉義符號去掉。

JsonPrimitive primitive = jsonElement.getAsJsonObject().get("data").getAsJsonPrimitive();
System.out.println("getAsString == " + primitive.getAsString());
System.out.println("toString == " + primitive.toString());            
複製程式碼

得到的結果是

getAsString == {"id":131,"appId":6,"versionCode":6014000}
toString == "{\"id\":131,\"appId\":6,\"versionCode\":6014000}"
複製程式碼

看這個執行結果可以知道通過getAsString(),得到的就是一個json串,而不是還帶有轉義字元的string,這種情況下,就可以通過 App app = new Gson().fromJson(primitive.getAsJsonPrimitive().getAsString(), App.class);得到具體的實體類模型了

以上只是簡單的情況,複雜的情況需要結合真實的實際場景來,使用標準的Gson api解析,這樣可以避免出現一些莫名其妙的問題

舉一個例子來描述這種場景:

image.png
這個程式碼片段試將後端的一個json資料轉換成了map的資料結構,我們看下結果

{code=200.0, message=ok, data=dataString}
複製程式碼

發現code被轉成了200.0,變成了double型別,這個問題在這裡不深究,想深究的可以看這個https://gist.github.com/xingstarx/5ddc14ff6ca68ba4097815c90d1c47cc,以及https://stackoverflow.com/a/36529534/5279354 總之在使用Gson解析的時候,不要只知道gson.from這一個api,沒事也需要多看看Gson相關的其他api,瞭解下Gson解析的工作原理,有助於我們更好的處理這類問題

附上完整的程式碼片段

@Test
    public void test2() {
        String json = "{\"code\":200, \"message\":\"ok\", \"data\":\"{\\\"id\\\":131,\\\"appId\\\":6,\\\"versionCode\\\":6014000}\"}";
        System.out.println("json == " + json);

        JsonElement jsonElement = new JsonParser().parse(json);
        if (jsonElement.isJsonNull()) {
        } else if (jsonElement.isJsonObject()) {
            JsonPrimitive primitive = jsonElement.getAsJsonObject().get("data").getAsJsonPrimitive();
            System.out.println("getAsString == " + primitive.getAsString());
            System.out.println("toString == " + primitive.toString());
            App app = new Gson().fromJson(primitive.getAsJsonPrimitive().getAsString(), App.class);
//            App app = new Gson().fromJson(primitive.getAsJsonPrimitive().toString(), App.class);
            System.out.println(app);
        } else if (jsonElement.isJsonArray()) {
        } else if (jsonElement.isJsonPrimitive()) {
        }

//        Map<String, Object> map = new LinkedTreeMap<>();
//        map = new Gson().fromJson(json, map.getClass());
//        System.out.println(map);
    }
複製程式碼

相關文章