1

I need to send objects from one socket to an other and I want to use JSON for serialization. It's necessary that every json object stores its type. My plan was to wrap my objects:

{
   /* the type */ "_type_": "my.package.MyClass",
   /* the actual object */ "_data_": {
      ...
   }
}

I tried to implement this by writing this serialization adapter

Gson gson = new GsonBuilder().registerTypeAdapter(Wrapper.class, new ObjectWrapperAdapter()).create();
gson.toJson(new Wrapper(myObject), Wrapper.class);

private static class ObjectWrapperAdapter implements JsonSerializer<Wrapper>, JsonDeserializer<Wrapper> {
    private static final String TYPE_KEY = "__type__";
    private static final String DATA_KEY = "__data__";

    @Override
    public Wrapper deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
        if(!json.isJsonObject()) throw new JsonParseException("element is not an object!");
        JsonObject object = json.getAsJsonObject();
        if(!object.has(TYPE_KEY)) throw new JsonParseException(TYPE_KEY + " element is missing!");
        if(!object.has(DATA_KEY)) throw new JsonParseException(DATA_KEY + " element is missing!");
        JsonElement dataObject = object.get(DATA_KEY);
        String clazzName = object.get(TYPE_KEY).getAsString();
        Class<?> clazz = classForName(clazzName);
        return new Wrapper(context.deserialize(dataObject, clazz));
    }

    private Class<?> classForName(String name) throws JsonParseException {
        try {
            return Class.forName(name);
        } catch (ClassNotFoundException e) {
            throw new JsonParseException(e);
        }
    }

    @Override
    public JsonElement serialize(Wrapper src, Type type, JsonSerializationContext context) {
        JsonObject wrapper = new JsonObject();
        Object data = src.object;
        JsonElement dataElement = context.serialize(data);
        String className = data.getClass().getName();
        wrapper.addProperty(TYPE_KEY, className);
        wrapper.add(DATA_KEY, dataElement);
        return wrapper;
    }
}

public static class Wrapper {
    private final Object object;

    public Wrapper(Object object) {
        this.object = object;
    }
}

In theory, this works, but it fails when I try to serialize nested objects, something like this

class MyType {
    AnotherType anotherType;
}

because only MyType will be wrapped and the resulting json will look something like this:

{
    "__type__": "my.package.MyType",
    "__data__": {
        (No "__type__" field here...)
        ...
    }
}

Is it possible to serialize objects with their types like this?

NyxCode
  • 584
  • 1
  • 4
  • 13
  • It looks like you are trying to solve a similar problem to [Gson - deserialization to specific object type based on field value](https://stackoverflow.com/questions/21767485/). Could you please check it and let us know whether the current problem is a duplicate? – Sergey Vyacheslavovich Brunov Jul 29 '17 at 23:39
  • 1
    @SergeyBrunov not really. I need a solution which works for every type/I dont know which types will be serialized... – NyxCode Jul 29 '17 at 23:45
  • Good, I see the point. Could you please take a look at these ones: [java - how to expose class names when serializing with Gson](https://stackoverflow.com/questions/19129711), [java - gson - How to include class name property when serializing object of any type](https://stackoverflow.com/questions/39999278)? – Sergey Vyacheslavovich Brunov Jul 29 '17 at 23:59
  • @SergeyBrunov Genson provides the functionality i was looking for. Thank you very much! A shame I havn't found the post on my own. – NyxCode Jul 30 '17 at 00:27
  • Glad it has helped you! Not a shame at all, we are here to help each other. – Sergey Vyacheslavovich Brunov Jul 30 '17 at 00:30

1 Answers1

0

This answer describes how to solve this problem. It does not use Gson but Genson instead. I dont really like how Genson handles Pojos, but I guess I have to live with that.

NyxCode
  • 584
  • 1
  • 4
  • 13
  • What don't you like in the way Gesnon handles Pojos? It is very similar to how Gson or Jackson handle them. – eugen Aug 02 '17 at 20:29