使用未知编译时类型反序列化通用,其中字段指示类型

时间:2011-03-27 17:29:48

标签: gson

这有效,但很糟糕 - 还有更好的方法吗?

我有一个泛型类,在这个简单的例子中如下

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...");
        }
    }
}

这让人感到非常笨拙和错误。还有更好的方法吗?

1 个答案:

答案 0 :(得分:1)

就当前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发布了一些简单的例子。