For several of my pet projects, I have had to interpret and/or send JSON WebSocket or HTTP responses in Java. I did some research and picked the library GSON to use. In each project, I have implemented a custom deserializer in order to correctly interpret different packet types.

For example:

> 
> 
> ```
> {"type": "set-name", "data":{"name":"daniel"}}
> {"type": "set-timeperiod", "data":{"start":"2017-03-16", "end":"2017-03-17"}}
> 
> ```
> 
> 

In this case I would use two classes, `SetName` and `SetTimePeriod`:

> 
> 
> ```
> public class SetName implements Data {
>     private String name;
> 
>     @Override
>     public void handle(Foo foo) throws InvalidPacketException {
>         if(name == null) throw new InvalidPacketException();
>         foo.doThingWithName(name);
>     }
> 
>     @Override
>     public String getType() { return "set-name"; }
> }
> 
> ```
> 
> 

`Foo` represents any arbitrary resources, the packet might need to perform its function. The data interface is fairly straightforward:

```
public interface Data {
    void handle(Foo foo);
    String getType();
}

```

The `Data` objects are wrapped in a Packet representing the whole thing:

```
public void Packet {
    private String type;
    private Data data;

    public Packet(Data data) {
        this.data = data;
        type = data.getType();
    }

    public void handle(Foo foo) throws InvalidPacketException { data.handle(foo); }

    public Packet initData(Data data) {
        if(this.data != null) throw new IllegalStateException("Data already initialised.");
        this.data = data;
        return this;
    }
}

```

And finally, the packet would be converted from raw JSON to an instance of `Packet` using a custom Deserializer.

```
public class PacketDeserializer implements JsonDeserializer<Packet> {

    @Override
    public Packet deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
        throws JsonParseException {
        JsonObject jsonObject = json.getAsJsonObject();
        // Remove data object, GSON won't know what to turn it into.
        JsonObject dataObject = jsonObject.remove("data").getAsJsonObject();
        // Determine what type of data object we need.
        Class dataClass = typeToClass(jsonObject.get("type").getAsString());
        // Construct and return a Packet of the correct type.
        Data data = context.deserialize(dataObject, dataClass);
        return new Gson().fromJson(jsonObject, Packet.class).initData(data);
    }

    private Class<? extends Data> typeToClass(String type) throws JsonParseException {
        switch(type) {
            case("set-name"): return SetName.class;
            case("set-timeperiod"): return SetTimePeriod.class;
            default: throw new JsonParseException("Type " + type + " is invalid.");
        }
    }
}

```

This means GSON will now deserialize the object into a `Packet` and then call the `handle()` to do whatever needs to be done with that packet:

```
Packet packet = new GsonBuilder()
    .registerTypeAdapter(Packet.class, new PacketDeserializer())
    .create()
    .fromJson(message, Packet.class);
packet.handle(foo);

```

In addition, a `Packet` instance can be converted to JSON without the need for any custom serializer. Once this structure is built, it is very easy to add new packet types or to send/parse packets.

This seems like an elegant solution to me, but I have some concerns:

* Is it actually efficient? Would it be much faster to parse the JSON directly?
* I can end up with a *lot* of subclasses of `Data` which makes me feel like there could be a better way of doing it
* If this is a good solution, would it be a good thing to use wherever I'm parsing JSON with some object with varying contents like `data`?

I came up with this solution years ago, when I was fairly new to programming and haven't changed it much at all, so I feel like I must be doing something wrong.