Полиморфизм или Наследование в JSON с Java и Ruby - PullRequest
3 голосов
/ 08 апреля 2009

Для контекста, мы храним большую часть наших данных в виде строк JSON. Это очень хорошо работает с Hadoop на бэкэнде и легко обрабатывается в Ruby на передней части. Мои типы данных соответствуют естественному шаблону наследования.

Для простоты, допустим, у меня есть класс Pet и процесс FeedPet, который кормит питомца. У меня также есть процесс WalkDog, который применяется только к собаке, которая является своего рода домашним животным. Мои данные организованы так, что мне не нужно беспокоиться о том, чтобы выгуливать животное, которое не является собакой.

Я бы хотел, чтобы Pet и Dog расширяли Pet, а у Dog был дополнительный метод "getLeash ()", но я не могу понять, как сопоставить это с JSON.

Вместо этого у меня есть класс Pet с хэш-картой данных видов, поэтому процесс WalkDog будет вызывать pet.getSpeciesData ("leash") вместо dog.getLeash ().

Я могу создать Dog extends Pet и сериализовать его в JSON, используя библиотеку Джексона. Объект JSON будет иметь поле привязи. Но предположим, что я хочу накормить всех питомцев. У всех домашних животных есть метод getFood (). Таким образом, процесс FeedPet десериализует объекты в Pet. Но это лишает поводка поля.

Процесс WalkDog может сделать это, потому что он знает, что все его входные данные будут собаками, поэтому он может читать его как собаку и записывать обратно как собаку.

Есть ли способ сериализации java-объектов в JSON, чтобы я мог сохранить их тип? Я думаю, что-то вроде Rails наследования одной таблицы, но это должно быть что-то, что понимают библиотеки JSON.

Ответы [ 2 ]

2 голосов
/ 09 апреля 2009

Для того, чтобы это работало, вы оба должны встраивать некоторую информацию о типе объекта в данные (где она полезна только для десериализации) и обычно использовать определение внешней схемы, которое в противном случае не понадобилось бы (например, XML-схема для xml), поскольку это в основном универсальный тип. система типов). Это имеет те же проблемы, что и ORM: Hibernate должен использовать уродливые обходные пути (n + 1 - двусторонние объединения, «супер таблицы» или поля дискриминатора).

Или другой способ выразить это: сопоставление / связывание данных не совсем то же самое, что сериализация / десериализация объекта (последний пытается сохранить больше идентичности объекта).

Здесь я предполагаю, что вы хотите что-то вроде:

Pet pet = mapper.readValue(jsonString, Pet.class);
// (and possibly get an exception if Pet is an abstract class...)
Leash l = ((Dog) pet).getLeash();

Если это не так, вы можете просто связать с Dog

Dog dog = mapper.readValue(jsonString, Dog.class);

Так или иначе: у проекта Джексона есть запрос о том, чтобы сделать именно это , что позволяет вам делать то, что (я думаю) вы хотите.

Однако это решение в основном будет работать для Java, поскольку не существует стандартного способа передачи информации о типе объекта в JSON. С XML это можно сделать с помощью определенной в XML-схеме атрибута «xsi: type»; который идентифицирует тип Schema, который затем отображается на класс (да, довольно сложный способ, но он работает).

ОБНОВЛЕНИЕ : Джексон 1.5 добавил поддержку для этого (т.е. реализовал запрос функции JACKSON-91), так что его можно использовать для генерации идентификаторов типов, чтобы обеспечить надлежащую обработку полиморфных типов , Он также должен работать с не-Java системами, учитывая, что вы можете полностью настроить детали того, как должна включаться информация о типах; и НЕ ограничивается использованием имен классов Java.

0 голосов
/ 08 апреля 2009

У меня не было такого большого опыта использования JSON, кроме как для приборов в django, но в этом случае у меня просто есть ключ "модели" со связанным значением.

Затем программа должна интерпретировать объекты для определения их типа и иерархии наследования.

То, что я пытаюсь сказать, это то, что не имеет значения, какие методы доступны, поскольку их не нужно сериализовать. Только имя объекта и атрибуты.

- обновление

После прочтения вашего вопроса кажется, что ваш процесс десериализуется в родительский класс, а не в реальный класс. Поскольку ваш класс собаки наследуется от питомца, вы просто должны убедиться, что ваш десериализатор создает объекты наиболее специализированного класса.

Я не знаю о библиотеке Джексона, но если вы можете установить для нее тип поля модели, тогда это может быть уместно.

...