2014-09-24 69 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