Достаточно просто использовать пользовательский JsonSerializer, который явно получает класс объекта (предположительно, по какой-то причине Gson получает объявленный тип вместо этого).Вот общее решение для сериализации интерфейсов:
public static class InterfaceSerializer<T> implements JsonSerializer<T> {
public JsonElement serialize(T link, Type type,
JsonSerializationContext context) {
// Odd Gson quirk
// not smart enough to use the actual type rather than the interface
return context.serialize(link, link.getClass());
}
}
Для вашего примера я могу сделать следующее:
GsonBuilder gbuild = new GsonBuilder();
Gson standard = gbuild.create();
ArrayList<Animal> animals = Lists.newArrayList(new Cat("Betty"),new Dog("Fred"));
System.out.println(standard.toJson(animals));
Container c = new Container();
c.animals.addAll(animals);
System.out.println(standard.toJson(c));
Gson interfaceAware = gbuild
.registerTypeAdapter(Animal.class, new InterfaceSerializer<>()).create();
System.out.println(interfaceAware.toJson(c));
Это выводит:
[{"name":"Betty","hates":"Everything"},{"name":"Fred","loves":"Everything"}]
{"animals":[{},{}]}
{"animals":[{"name":"Betty","hates":"Everything"}, "name":"Fred","loves":"Everything"}]}
Последнийitem является правильно сериализованной строкой.
Этого недостаточно для десериализации JSON, к сожалению, потому что результирующий JSON не содержит никакой информации о типе.Посмотрите этот ответ на вопрос Как сериализовать класс с интерфейсом? , чтобы узнать способ отслеживания типа объекта и, следовательно, сериализации / десериализации объекта.