在不知道.class的情况下,如何使用Gson从Java中的JSON反序列化和返回对象?

在不知道.class的情况下,如何使用Gson从Java中的JSON反序列化和返回对象?,java,json,generics,gson,Java,Json,Generics,Gson,我目前正在开发一个瘦客户机应用程序,通过JSON序列化的消息对象进行通信。服务器序列化消息,通过套接字发送消息,客户端接收并反序列化消息。答案也是这样 首先,假设消息类是在服务器和客户端上定义的 问题是Gson::fromJson函数需要一个.class/type对象通过内省进行反序列化(这是可以理解的),但在我的应用程序中,可以在不事先知道.class的情况下接收多种类型的对象 我的想法是创建一个如下的消息包装器: class MessageWrapper { public class

我目前正在开发一个瘦客户机应用程序,通过JSON序列化的消息对象进行通信。服务器序列化消息,通过套接字发送消息,客户端接收并反序列化消息。答案也是这样

首先,假设消息类是在服务器和客户端上定义的

问题是
Gson::fromJson
函数需要一个.class/type对象通过内省进行反序列化(这是可以理解的),但在我的应用程序中,可以在不事先知道.class的情况下接收多种类型的对象

我的想法是创建一个如下的消息包装器:

class MessageWrapper {
    public class MessageWrapper(Object message, MessageType type) {
        this.message = message;
        this.type = type;
    }

    // getters...

    public enum MesssageType {
        PLACEMENT,
        UPDATE,
        // ...
    }

    private final Object message;
    private final MessageType type;
}
甚至可以通过内省来确定
类型
参数。这个解决方案非常适合序列化(我重复一遍,这不是问题),但是在反序列化时,我会得到消息类型并释放消息本身,至少如果我不分析它两次的话。通过Java“模板化”机制专门化MessageWrapper使我们回到了最初的问题(我将有多个类可供选择)

另一个想法是在JSON字符串之前发送一个标识消息的令牌,如:

Placement={"foo": 2, "bar": "baz"}
然后读取标记以确定.class类型。这可能会起作用,但仍然存在一个问题:如何从我的
receive
函数返回值?
当然可以:

public Object receive(Reader stream) {}
并强制用户进行向下广播,但我宁愿避免这样做

编辑:这是因为客户端有一个类似于reactor的结构:它在循环中运行,并将消息分派给适当的处理程序。

编辑:

好了,现在更清楚了

有一个包含一系列已定义对象的包装器怎么样?你有多少个处理器

我的意思是:

class HandlerWrapper {
    private final Placement placement;
    private final Update update;
}
然后,客户端将对此进行反序列化并检查not null属性:

{“placement”:{“foo”:2,“bar”:“baz”},“update”:null,}

我知道这不是很好,但我想不出其他的事情/


旧的

我不认为这实际上是一个问题,因为您可以在您的规范中说明您必须从特定情况中期望什么类型的对象

例如,如果要调用API来获取用户,则对象中需要User.class。API获得一本书(或其他)也是如此


(我希望我理解了这个问题)

使用Gson,如果您有合理数量的可能消息,您可以创建一个包含所有消息的类(类似于@Enrichman编写的,但不需要检查null…)。例如,如果你有这个类

public class Response {
    private Placement placement;
    private Update update;
    //more message types
    //getters & setters
}
然后,您可以使用以下命令反序列化您的响应:

Gson gson = new Gson();
Response response = gson.fromJson(jsonString, Response.class);
它将反序列化这个JSON:

{"placement": {...} }
这是:

{"update": {...} }
{"placement": {...}, "update": {...} }
这是:

{"update": {...} }
{"placement": {...}, "update": {...} }

Gson将忽略JSON响应中与类中的任何属性都不对应的所有字段,因此您可以使用单个类来反序列化多个响应…

您可以更改从服务器发送的结构吗?我的意思是使用另一个库并在流中添加类型信息。我在生成的JSON中有类型信息,可以是字段(第一种情况),也可以是类型令牌(后一种情况)。答案很好。我接受这一点,因为它概括了“空字段未序列化”这一关键点,并提升了另一个,因为它提供了关键直觉。遗憾的是,我不能用一种更简单的方法获得同样的结果,也许一些CGlib魔术可以做到。顺便说一句,你可以选择序列化或非空字段(至少你可以用Jackson:)实现这一点。)