使用未知的编译时类型对字段进行反序列化,其中字段指示类型 [英] Deserialising a generic with unknown compile time type where a field indicates the type
问题描述
public class MsgWrapper< T> {
@Expose
private T消息;
@Expose
私人字符串类型;
private String uri;
}
串行化是令人讨厌的,但是微不足道的,例如
类型typeToken = new TypeToken< MsgWrapper< Notice>>(){}。getType();
gson.toJson(message,typeToken);
服务器收到的json可以是
MsgWrapper<公告>或MsgWrapper< Alert>
如果是通知,那么'类型'字段会显示'notice'
If它是一个提示,然后'类型'字段将会显示'alert'。
目前我已经实现了一个自定义的反序列化程序
public MsgWrapper deserialize(JsonElement json,Type typeOfT,JsonDeserializationContext context)throws JsonParseException {
JsonObject object = json.getAsJsonObject();
if(object.has(Type))
{
MsgWrapper msgWrapper = new MsgWrapper();
msgWrapper.setType(object.get(Type)。getAsString());
if(msgWrapper.getType()。equalsIgnoreCase(Notice))
{
msgWrapper.setMessage(context.deserialize(object.get(Message),Notice.class)) ;
else if(msgWrapper.getType()。equalsIgnoreCase(Alert))
{
msgWrapper.setMessage(context.deserialize(object.get(Message)) ,Alert.class));
}
return msgWrapper;
}
else
{
抛出新的JsonParseException(出错了......);
}
}
}
这感觉非常笨重和错误。有没有更好的方法?
您发布的解决方案或多或少的多达多少与当前Gson版本的反序列化有关。
您可以实施一些小的更改,以使外部可自定义的解串器可配置,就像Dan提到的那样,使用 Map< String,Deserializer>
。
不用定制解串器,看起来Gson很快就会拥有 RuntimeTypeAdapter
可用于更简单的多态反序列化。请参阅 http://code.google.com/p/google- gson / issues / detail?id = 231 了解更多信息。即使您不能使用 RuntimeTypeAdapter
,它至少提供了一个创建可配置的自定义反序列化器的示例。
如果您可以切换JSON映射API,然后我建议考虑Jackson,因为它具有可用的相对简单的多态解串器机制。我在 http://programmerbruce.blogspot上发布了一些简单的示例.com / 2011/05 / deserialize-json-with-jackson-into.html 。
This works but it is horrible - is there a better way?
I have a generic class which in this simple example is as follows
public class MsgWrapper<T> {
@Expose
private T Message;
@Expose
private String Type;
private String uri;
}
Serialising is nasty but trivial e.g.
Type typeToken = new TypeToken<MsgWrapper<Notice>>(){}.getType();
gson.toJson(message,typeToken);
The server receives json which can be either
MsgWrapper<Notice> or MsgWrapper<Alert>
If it is a notice then the 'Type' field will say 'notice' If it is an alert then the 'Type' field will say 'alert'
At the moment I've implemented a custom deserialiser
public MsgWrapper deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject object = json.getAsJsonObject();
if(object.has("Type"))
{
MsgWrapper msgWrapper=new MsgWrapper();
msgWrapper.setType(object.get("Type").getAsString());
if(msgWrapper.getType().equalsIgnoreCase("Notice"))
{
msgWrapper.setMessage(context.deserialize(object.get("Message"), Notice.class));
}
else if(msgWrapper.getType().equalsIgnoreCase("Alert"))
{
msgWrapper.setMessage(context.deserialize(object.get("Message"), Alert.class));
}
return msgWrapper;
}
else
{
throw new JsonParseException("something is wrong...");
}
}
}
This feels deeply clunky and wrong. Is there a better way?
The solution you posted is more-or-less as good as it gets as far as polymorphic deserialization with the current Gson release is concerned.
You could implement some small changes to make the custom deserializer externally configurable, along the lines as Dan suggested with the mention of changing to use Map<String, Deserializer>
.
Instead of using a custom deserializer, it looks like Gson will soon have the RuntimeTypeAdapter
available for simpler polymorphic deserialization. See http://code.google.com/p/google-gson/issues/detail?id=231 for more info. Even if you cannot use the RuntimeTypeAdapter
, it at least provides an example for creating a configurable custom deserializer.
If you can switch JSON mapping APIs, then I recommend considering Jackson, as it has a working and relatively simple polymorphic deserializer mechanism available. I posted some simple examples at http://programmerbruce.blogspot.com/2011/05/deserialize-json-with-jackson-into.html.
这篇关于使用未知的编译时类型对字段进行反序列化,其中字段指示类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!