2013-03-22 104 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; 
}