2016-08-19 78 views
0

以下是问题域的类图。我们有不同的语义JSON解码的消息,这些语义触发不同视图的代码中的不同方法(初始化,更新)。Gson反序列化多态成员列表变量为空

Message使用使用RuntimeTypeAdapterFactory和注册的所有可能的亚型的溶液提出here反序列化细成要么InitMessageDataMessage。但是,DataMessage.value列表为空(未反序列化)。问题是DataMessage中的嵌套多态成员。

Class diagram of the problem domain

适配器工厂:

RuntimeTypeAdapterFactory<Message> messageAdapterFactory = RuntimeTypeAdapterFactory 
    .of(Message.class, "MESSAGE_TYPE") 
    .registerSubtype(InitializationMessage.class, "INIT") 
    .registerSubtype(DataMessage.class, "DATA"); 

RuntimeTypeAdapterFactory<DataValue> dataAdapterFactory = RuntimeTypeAdapterFactory 
    .of(DataValue.class, "NAME") 
    .registerSubtype(DataValueA.class, "A") 
    .registerSubtype(DataValueB.class, "B") 
    .registerSubtype(DataValueC.class, "C"); 

消息的创建:

TypeToken<Message> typeToken = new TypeToken<Message>() {}; 
Message msg = gson.fromJson(json, typeToken.getType()); 

DataMessage类:

public class DataMessage extends Message { 

    private List<DataValue> value; 

    public List<DataValue> getValue() { 
    return value; 
    } 

    public void setValue(List<DataValue> value) { 
    this.value= value; 
    } 
} 

d ataValueA类:

public class DataValueA extends DataValue { 

    private Map<String, Float> value; 

    public float getValue(String location) { 
    return value.get(location); 
    } 
} 

相应的JSON:

{ 
    "MESSAGE_TYPE" : "DATA", 
    "VALUE" : [ 
    { 
     "NAME" : "C", 
     "VALUE" : 1.3 
    }, 
    { 
     "NAME" : "A", 
     "VALUE" : { 
      "FL" : 18.4, 
      "FR" : 18.4, 
      "RL" : 18.4, 
      "RR" : 18.4 
     } 
    }] 
} 

我想DataValue反序列化到其各自的子类(DataValueA ...)。

+0

为'Message'写了一个'JsonDeserializer',它创建了正确的子类,并通过'context来委托进一步的反序列化。 反序列化(dataObject,DataValue.class)使我能够使用多态数据反序列化多态信息。但是,我完全失去了使用'RuntimeTypeAdapterFactory'提供的数据绑定代码的可读性和可维护性。 – lschuetze

回答

1

解决方法是使用GsonBuilder.registerTypeAdapter方法注册自定义JsonDeserializer。方法是使用消息中的字段来定义将创建哪个子类(就像RuntimeTypeAdapterFactory默认情况下未发货并且位于gson-extra中)。

反串行器将被注册为每个抽象超类。

gson = new GsonBuilder() 
    .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) 
    .registerTypeAdapter(Message.class, new MessageAdapter()) 
    .registerTypeAdapter(DataValue.class, new DataValueAdapter()) 
    .create(); 

鉴于外地来区分亚型命名为NAME可以定义反序列化功能如下。从字段的内容到相应的子类有一个映射。

public class DataValueAdapter implements JsonDeserializer<DataValue> { 
    private final static Map<String, Class<?>> FieldToClass; 

    static { 
    FieldToClass = new HashMap<>(); 
    FieldToClass.put("PERFORMANCE", PerformanceDataValue.class); 
    FieldToClass.put("TIRE_SLIP", TireSlipDataValue.class); 
    } 

    @Override 
    public DataValue deserialize(JsonElement json, Type typeOfT, 
           JsonDeserializationContext context) throws JsonParseException { 
    JsonObject jsonObject = json.getAsJsonObject(); 
    String dataType = jsonObject.get("NAME").getAsString(); 
    return context.deserialize(json, FieldToClass.get(dataType)); 
    } 
} 

为了使反射解串器(将,只要你已经符合标准解串器用于子类)工作的子类需要国家@SerializedName的性能。没有它不适合我。