反序列化具有未知编译时类型的泛型,其中字段指示类型
这可行,但很糟糕 - 有更好的方法吗?
我有一个通用类,在这个简单的示例中如下
public class MsgWrapper<T> {
@Expose
private T Message;
@Expose
private String Type;
private String uri;
}
序列化很讨厌但微不足道,例如
Type typeToken = new TypeToken<MsgWrapper<Notice>>(){}.getType();
gson.toJson(message,typeToken);
服务器接收 json,它可以
MsgWrapper<Notice> or MsgWrapper<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
{
throw new JsonParseException("something is wrong...");
}
}
}
这感觉非常笨拙和错误。有更好的办法吗?
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
就当前 Gson 版本的多态反序列化而言,您发布的解决方案或多或少是一样好的。
您可以实现一些小的更改,以使自定义解串器在外部可配置,按照 Dan 建议的方式,并提到更改为使用
Map
。看起来 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。
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 theRuntimeTypeAdapter
, 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.