How to deserialize and return JSON objects in Java with Gson without knowing the. Class a priori?

advertisements

I am currently working on a thin-client application, where the communication happens through JSON-serialized message objects. 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.

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. 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).

Another idea, was to send a token to identify the message, before the JSON string, like:

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

Then read the token to determine the .class type. This could work, but there is still a problem: how would I return the value from my receive function? 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.


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...). 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:

{"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...