2013-03-22 114 views
4

我解析有類似這樣的響應模板數據解析的子類:使用GSON不同領域

{ 
    response: { 
    data: {} 
    } 
    meta: { 
    errors: [] 
    success: 1 
    } 
} 

對於每一個具體的響應,「數據」字段中填入動態字段,但所有其他鍵(元等)保持不變。例如:

ClassA的

data: { 
    foo: "" 
} 

ClassB的

data: { 
    bar: 3 
} 

我怎麼可以模擬我的課,用GSON來表示這個數據?目前,我已經有了:

public class BaseResponse { 
    @SerializedName("meta") public Meta meta; 

    public class Meta { 
    @SerializedName("errors") public ArrayList<Error> errors; 
    @SerializedName("success") public int success; 
    } 
} 

public class ClassA extends BaseResponse { 
    @SerializedName("foo") public String foo; 
} 

public class ClassB extends BaseResponse { 
    @SerializedName("bar") public int bar; 
} 

不幸的是,foo和bar領域解析時返回空值,使用,例如:

Gson.fromJson(jsonString, ClassA.class); 

我相信這是由於「foo」和「酒吧「領域是內在的參考。

+0

我不知道很多關於GSON但​​是當你說,解析返回NULL,究竟是什麼jsonString的價值時,你叫'Gson.fromJson(jsonString,ClassA.class);'? – 2013-03-22 19:24:29

+0

對於ClassA的響應它看起來像{ 響應:{ 數據:{FOO: 「富」} } 元:{ 錯誤:[] 成功:1 } } – Rockmaninoff 2013-03-22 19:33:24

+0

對於ClassB的響應它看起來像{響應:{data:{bar:350}} meta:{errors:[] success:1}} – Rockmaninoff 2013-03-22 19:33:50

回答

6

正如我所理解的問題,自定義處理是必要的,以提供所需的多態反序列化,其中決定使用哪種類型是基於特定的JSON元素名稱的存在。 (因爲JSON不包含類型信息,切換到另一個序列化API,如Jackson,也不會提供一個簡單的解決方案。)

下面演示我想可能採取的做法。

package com.stackoverflow.q15578106; 

import java.lang.reflect.Type; 
import java.util.HashMap; 
import java.util.List; 
import java.util.Map; 

import com.google.gson.Gson; 
import com.google.gson.GsonBuilder; 
import com.google.gson.JsonDeserializationContext; 
import com.google.gson.JsonDeserializer; 
import com.google.gson.JsonElement; 
import com.google.gson.JsonObject; 
import com.google.gson.JsonParseException; 

public class Foo 
{ 
    public static void main(String[] args) 
    { 
    /* 
     { 
     "response": {"data": {"foo": "FOO"}}, 
     "meta": {"errors": [], "success": 1} 
     } 
    */ 
    String input1 = "{\"response\": {\"data\": {\"foo\": \"FOO\"}},\"meta\": {\"errors\": [], \"success\": 1}}"; 

    /* 
     { 
     "response": {"data": {"bar": 42}}, 
     "meta": {"errors": [], "success": 1} 
     } 
    */ 
    String input2 = "{\"response\": {\"data\": {\"bar\": 42}},\"meta\": {\"errors\": [], \"success\": 1}}"; 

    processInput(input1); 
    // {"response":{"data":{"foo":"FOO"}},"meta":{"errors":[],"success":1}} 

    processInput(input2); 
    // {"response":{"data":{"bar":42}},"meta":{"errors":[],"success":1}} 
    } 

    static void processInput(String jsonInput) 
    { 
    DataDeserializer dataDeserializer = new DataDeserializer(); 
    dataDeserializer.registerDataType("foo", A.class); 
    dataDeserializer.registerDataType("bar", B.class); 

    Gson gson = new GsonBuilder().registerTypeAdapter(Data.class, dataDeserializer).create(); 

    BaseResponse response = gson.fromJson(jsonInput, BaseResponse.class); 
    System.out.println(new Gson().toJson(response)); 
    } 
} 

class DataDeserializer implements JsonDeserializer<Data> 
{ 
    Map<String, Class<? extends Data>> dataTypeRegistry = new HashMap<String, Class<? extends Data>>(); 

    void registerDataType(String jsonElementName, Class<? extends Data> javaType) 
    { 
    dataTypeRegistry.put(jsonElementName, javaType); 
    } 

    @Override 
    public Data deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException 
    { 
    JsonObject jsonObject = json.getAsJsonObject(); 
    for (String elementName : dataTypeRegistry.keySet()) 
    { 
     if (jsonObject.has(elementName)) 
     { 
     Class<? extends Data> dataType = dataTypeRegistry.get(elementName); 
     return context.deserialize(jsonObject, dataType); 
     } 
    } 
    throw new RuntimeException("Oops"); 
    } 
} 

class BaseResponse 
{ 
    Response response; 
    Meta meta; 
} 

class Meta 
{ 
    List<String> errors; 
    int success; 
} 

class Response 
{ 
    Data data; 
} 

class Data 
{ 

} 

class A extends Data 
{ 
    String foo; 
} 

class B extends Data 
{ 
    int bar; 
}