简体   繁体   English

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

[英]How to deserialize and return objects from JSON in Java with Gson without knowing the .class a priori?

I am currently working on a thin-client application, where the communication happens through JSON-serialized message objects. 我目前正在开发瘦客户端应用程序,该应用程序通过JSON序列化的消息对象进行通信。 Server serializes the message, sends it through a socket, client receives and deserializes. 服务器将消息序列化,通过套接字发送,客户端接收并反序列化。 Answers happen in the same way. 答案以相同的方式发生。

First, let's assume the message class are defined both on server and client. 首先,假设消息类在服务器和客户端上均已定义。

Problem is that Gson::fromJson function needs a .class/type object for deserializing via introspection (understandably), but in my application, multiple type of objects can be received without knowing the .class in advance. 问题是Gson::fromJson函数需要一个.class / type对象用于通过自省反序列化(可以理解),但是在我的应用程序中,可以接收多种类型的对象,而无需事先知道.class。

My idea was to create a message wrapper like this: 我的想法是创建一个像这样的消息包装器:

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;
}

Or even go further by determining type param with introspection. 甚至可以通过内省来确定type param,从而走得更远。 This solution is great for serializing (I repeat, that is not a problem), but while deserializing I would get the message type and loose the message itself, at least if I don't parse it twice. 这个解决方案非常适合序列化(我再说一遍,这不是问题),但是在反序列化时,我将获得消息类型并释放消息本身,至少如果我不两次解析它。 Specializing MessageWrapper through Java "templating" mechanism brings us back to the original problem (I would have multiple classes to choose from). 通过Java“模板”机制专门化MessageWrapper可以使我们回到最初的问题(我将有多个类可供选择)。

Another idea, was to send a token to identify the message, before the JSON string, like: 另一个想法是在JSON字符串之前发送令牌以标识消息,例如:

Placement={"foo": 2, "bar": "baz"}

Then read the token to determine the .class type. 然后读取令牌以确定.class类型。 This could work, but there is still a problem: how would I return the value from my receive function? 这可能有效,但是仍然存在问题: 如何从我的receive函数返回值? Of course I could do: 我当然可以:

public Object receive(Reader stream) {}

And force the user to do a downcast, but I'd rather avoid it. 并强迫用户进行向下转换,但我宁愿避免这种情况。

EDIT: this is because the client has a reactor-like structure: it runs in a loop and dispatches messages to appropriate handlers. 编辑:这是因为客户端具有类似反应堆的结构:它在循环中运行并将消息分派到适当的处理程序。

EDIT: 编辑:

Ok, now it's clearer. 好的,现在更清楚了。

What about having a Wrapper with a series of defined Objects? 拥有一个带有一系列已定义对象的包装怎么样? How many handlers do you have? 您有几个处理程序?

I mean something like: 我的意思是:

class HandlerWrapper {
    private final Placement placement;
    private final Update update;
}

then the client will deserialize this and check for the not-null property: 然后客户端将反序列化并检查not-null属性:

{"placement":{"foo": 2, "bar": "baz"}, "update":null, ...}

I knwo it's not very nice but I cannot think about something else.. : / 我知道这不是很好,但是我不能考虑其他事情。


OLD

I don't think this is actually a problem, because you can say in your specification what kind of object you have to expect from that specific case. 我不认为这实际上是一个问题,因为您可以在规范中说出在特定情况下必须期望什么样的对象。

For example, if you're calling an API to get a User, you will expect a User.class in the Object. 例如,如果您要调用API来获取用户,则将在对象中使用User.class。 The same for an API to get a Book (or whatelse). 获取书籍(或其他书籍)的API同样如此。

(I hope I understood the question) (希望我能理解这个问题)

Using Gson, if you have a reasonable number of possible messages, you could create a class containing all of them (something similar to which @Enrichman wrote, but you don't need to check for nulls...). 使用Gson,如果您有足够数量的可能消息,则可以创建一个包含所有消息的类(类似于@Enrichman编写的类,但无需检查null ...)。 For example if you have the class 例如,如果您有课程

public class Response {
    private Placement placement;
    private Update update;
    //more message types
    //getters & setters
}

Then you can deserialize your response with: 然后,您可以使用以下方法反序列化您的响应:

Gson gson = new Gson();
Response response = gson.fromJson(jsonString, Response.class);

And it would deserialize this JSON: 它将反序列化此JSON:

{"placement": {...} }

and this: 和这个:

{"update": {...} }

and this: 和这个:

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

Gson will ignore all the fields in the JSON response that don't correspond to any attribute in your class, so you can use a single class to deserialize multiple responses... Gson将忽略JSON响应中与类中任何属性都不对应的所有字段,因此您可以使用单个类对多个响应进行反序列化...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM