How to serialize a class with an interface?

Solution 1:

Here is a generic solution that works for all cases where only interface is known statically.

  1. Create serialiser/deserialiser:

    final class InterfaceAdapter<T> implements JsonSerializer<T>, JsonDeserializer<T> {
        public JsonElement serialize(T object, Type interfaceType, JsonSerializationContext context) {
            final JsonObject wrapper = new JsonObject();
            wrapper.addProperty("type", object.getClass().getName());
            wrapper.add("data", context.serialize(object));
            return wrapper;
        }
    
        public T deserialize(JsonElement elem, Type interfaceType, JsonDeserializationContext context) throws JsonParseException {
            final JsonObject wrapper = (JsonObject) elem;
            final JsonElement typeName = get(wrapper, "type");
            final JsonElement data = get(wrapper, "data");
            final Type actualType = typeForName(typeName); 
            return context.deserialize(data, actualType);
        }
    
        private Type typeForName(final JsonElement typeElem) {
            try {
                return Class.forName(typeElem.getAsString());
            } catch (ClassNotFoundException e) {
                throw new JsonParseException(e);
            }
        }
    
        private JsonElement get(final JsonObject wrapper, String memberName) {
            final JsonElement elem = wrapper.get(memberName);
            if (elem == null) throw new JsonParseException("no '" + memberName + "' member found in what was expected to be an interface wrapper");
            return elem;
        }
    }
    
  2. make Gson use it for the interface type of your choice:

    Gson gson = new GsonBuilder().registerTypeAdapter(Animal.class, new InterfaceAdapter<Animal>())
                                 .create();
    

Solution 2:

Put the animal as transient, it will then not be serialized.

Or you can serialize it yourself by implementing defaultWriteObject(...) and defaultReadObject(...) (I think thats what they were called...)

EDIT See the part about "Writing an Instance Creator" here.

Gson cant deserialize an interface since it doesnt know which implementing class will be used, so you need to provide an instance creator for your Animal and set a default or similar.