2014-09-24 21 views
3

我使用GSON到Java對象轉換爲從JSON對象。我碰到了一個多態的問題。GSON - 自定義解串器的多態變量

我有這方面的要求,看起來是這樣的:

{ 
    "method": "getUser", 
    "methodParameters": { 
    "a": "b", 
    "c": "d", 
    "e": "f", 
    "data": { 
     "u": "v", 
     "x": "y" 
    } 
    }, 
    "version": "1.3" 
} 

每個請求方法都有不同種類的數據對象。當然,每個數據對象都會擴展名爲RequestData的基類。

我試圖創建一個自定義解串器,但因爲它是請求對象,而不是保存方法的數據對象,我無法找到一個方法來知道哪些對象進行反序列化到。

是否有可能反序列化數據對象時,以某種方式獲取方法值或者是有一些其他更好的辦法來解決這個問題?謝謝。

回答

2

我遇到了類似的問題:由託梅克指出你需要一個定製的解串器,與您可以使用它在運行時,其子類決定實例特定的JSON場一起。

考慮下面的類作爲基類:

// Base class for a server sent event 
public class ServerEvent 
{ 
    public static final String TYPEFIELDNAME = "eventType"; 

    // Event type is used during deserialization to choose the right subclass 
    private final String eventType; 

    public ServerEvent(String eventType) 
    { 
     this.eventType = eventType; 
    } 

    public String toString() 
    { 
     return "eventType: " + eventType; 
    } 
} 

ServerEvent有兩個子類,每一個具有不同性質:

public class EventA extends ServerEvent 
{ 
    private static final String EVENTTYPE = "eventa"; 
    private int data; 

    public EventA() 
    { 
     super(EVENTTYPE); 
    } 

    // Helper function to register this class with ServerEventDeserializer 
    public static void register(ServerEventDeserializer deserializer) 
    { 
     deserializer.registerEvent(EVENTTYPE, EventA.class); 
    } 

    public String toString() 
    { 
     return super.toString() + ", data = " + data; 
    } 
} 

public class EventB extends ServerEvent 
{ 
    private static final String EVENTTYPE = "eventb"; 
    private String name; 

    public EventB() 
    { 
     super(EVENTTYPE); 
    } 

    // Helper function to register this class with ServerEventDeserializer 
    public static void register(ServerEventDeserializer deserializer) 
    { 
     deserializer.registerEvent(EVENTTYPE, EventB.class); 
    } 

    public String toString() 
    { 
     return super.toString() + ", name = " + name; 
    } 
} 

兩個可能的輸入可以是以下各項:

{ "eventType" : "eventa", "data" : 15 } 
{ "eventType" : "eventb", "name" : "test" } 

這是多態的解串器:

// This class handles the polymorphic deserialization of ServerEvent class 
public class ServerEventDeserializer implements JsonDeserializer<ServerEvent> 
{ 
    // Gson engine 
    private Gson gson; 

    // Map of subclasses 
    private Map<String, Class<? extends ServerEvent>> eventRegistry; 

    public ServerEventDeserializer() 
    { 
     gson = new Gson(); 
     eventRegistry = new HashMap<String, Class<? extends ServerEvent>>(); 
    } 

    // Registers a ServerEvent subclass 
    public void registerEvent(String event, Class<? extends ServerEvent> eventInstanceClass) 
    { 
     eventRegistry.put(event, eventInstanceClass); 
    } 

    @Override 
    public ServerEvent deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException 
    { 
     try 
     { 
      // Get the JSON object 
      JsonObject commandObject = json.getAsJsonObject(); 

      // Read the field named "ServerEvent.TYPEFIELDNAME" 
      JsonElement commandTypeElement = commandObject.get(ServerEvent.TYPEFIELDNAME); 

      // Query the eventRegistry map to instance the right subclass 
      Class<? extends ServerEvent> commandInstanceClass = eventRegistry.get(commandTypeElement.getAsString()); 
      ServerEvent command = gson.fromJson(json, commandInstanceClass); 

      return command; 
     } 
     catch (Exception e) 
     { 
      throw new RuntimeException(e); 
     } 
    } 
} 

我寫了一個最小工作例子,可以下載here

0

當你反序列化這個例子JSON字符串定製解串器將有方法的標題那樣:(在GsonBuilder對象由registerTypeAdapter(添加此解串器)方法)

public YOUR_CLASS deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 

可以JsonElement轉換爲字符串,提取您的methodParameters並基於每個RequestData子類的典型特性,您可以實例化特定的類。例如,假設我們有MyRequestData,這個類有10個參數。我正在檢查我的json字符串,如果它有這麼多參數返回這個特定的實例。當然,您可以先將方法參數(在反序列化程序類中)反序列化爲Map類,然後分析它以選擇正確的類。

+0

感謝您的回答!由於兩種方法可以具有相同數量的參數,因此我無法查看參數的數量。他們甚至應該能夠擁有完全相同的參數。你能否詳細說明methodparams的反序列化? – anony115511 2014-09-24 11:24:04

+0

以後我會的。但是我有個問題,這些類有什麼區別?只有執行某些方法?在這種情況下,不可能識別它們。然後,您可以簡單地添加額外的參數,例如「name」和特定類的構造函數集名稱。這將是最簡單的解決方案。那麼反序列化將很容易。 – Tomek 2014-09-24 11:30:41