Это ожидаемое поведение. У Gson есть список объектов по умолчанию TypeAdapterFactory
. Вы можете видеть их в source of the Gson class.
Есть адаптеры для String
, Number
, Map
, Collection
... Последний является важным и используются, когда никакие переходники не могут обрабатывать тип: это ReflectiveTypeAdapter
. Он извлекает путем отражения все поля объекта для сериализации и ищет соответствующие адаптеры для сериализации значений полей.
Итак, когда Gson должен сериализовать объект, сначала он пытается найти адаптер, используя фактический тип объекта. Если найденный адаптер не является ReflectiveTypeAdapter
, он использует его. В противном случае он ищет адаптер с декларативным типом и использует его, если это не ReflectiveTypeAdapter
. В противном случае он использует ReflectiveTypeAdapter
на объекте (вы можете посмотреть на источник класса TypeAdapterRuntimeTypeWrapper, чтобы получить более подробную информацию об этом mecanism). Это поведение, которое у вас есть с вашим атрибутом MyInterface i
.
Когда вы делаете:
MyInterface i = new MyConcreteClass();
String json = gson.toJson(i);
Gson пытается найти адаптер для типа MyConcreteClass
и он находит ReflectiveTypeAdapter
. Теперь он должен искать адаптер с декларативным типом. Но он не имеет возможности узнать декларативный тип, потому что ни один объект не ссылается на него, это корневой объект. Вы знаете в своем коде, что хотите использовать тип MyInterface
, но Gson не имеет этой информации и имеет только экземпляр объекта. Вы можете подумать, что Gson мог видеть, что объект реализует MyInterface
, но это не так, как он работает (и что делать, если объект реализует два интерфейса?)
Итак, у вас есть два пути, чтобы решить вашу проблему:
1) При вызове Gson.toJson
, вы можете дать декларативного типа для корневого объекта: Gson#toJson(Object, Type)
String json = gson.toJson(i, MyInterface.class);
2) Когда вы зарегистрировать адаптер, вы можете указать, что этот адаптер относится ко всем подклассам: GsonBuilder#registerTypeHierarchyTree
GsonBuilder builder = new GsonBuilder()
.registerTypeHierarchyAdapter(MyInterface.class, new MySerializer());
Надеется, что это помогает
Спасибо за ответ. Тем не менее, я думаю, что это ожидаемый * дефект * из-за ограничения Java. –
Когда я использую registerTypeHierarchyAdapter Я застреваю в непрерывном цикле, когда метод serialize выполняет result.add («properties», context.serialize (src, src.getClass())) –