Что такое хорошая стратегия для преобразования объектов jpa в резервные ресурсы
У остальных ресурсов не всегда есть сопоставление "один к одному" с вашими объектами jpa. Как я вижу, есть несколько проблем, которые я пытаюсь выяснить, как обращаться:
- Когда ресурс имеет информацию, которая заполняется и сохраняется несколькими объектами.
- Когда объект имеет больше информации в нем, которую вы хотите отправить в качестве ресурса. Я мог бы просто использовать Jackson
@JsonIgnore
, но у меня все равно были бы проблемы с 1, 3 и 4.
- Когда объект (например, совокупный корень) имеет вложенные объекты и вы хотите включить часть своих вложенных объектов, но только к определенному уровню вложенности в качестве вашего ресурса.
- Если вы хотите исключить один кусок объекта, когда его часть одного родительского объекта, но исключает отдельную часть, когда ее часть другого родительского объекта.
- Взорванные циклические ссылки (я получил это в основном с JSOG с помощью Jackson
@JsonIdentityInfo
)
Возможные решения:
Единственный способ, с помощью которого я мог бы подумать, будет справляться со всеми этими проблемами, - это создать целую кучу классов ресурсов, которые имели бы конструкторы, которые занимали бы необходимые объекты для создания ресурса и размещали на нем необходимые геттеры и сеттеры для этого ресурса, Это перебор?
Чтобы решить 2, 3, 4 и 5, я мог бы просто выполнить предварительную и пост-обработку на фактическом объекте перед отправкой его в Jackson для сериализации или десериализации моего pojo в JSON, но это не касается проблемы 1.
Это все проблемы, которые я бы подумал, что другие столкнулись бы, и мне любопытно, какие решения могут предложить другие люди. (В настоящее время я использую JPA 2, Spring MVC, Jackson и Spring -Data, но открыт для других технологий)
Ответы
Ответ 1
С помощью комбинации JAX_RS 1.1 и Jackson/GSON вы можете напрямую представлять объекты JPA в качестве ресурсов REST, но вы столкнетесь с множеством проблем.
DTO, то есть проекции на объекты JPA - это путь. Это позволит вам отделить проблемы представления ресурсов от REST от транзакционных проблем JPA. Вы четко определяете характер представлений. Вы можете контролировать объем данных, отображаемых в представлении, включая глубину пройденного графика объекта, если вы тщательно разработаете свои DTO/прогнозы. Возможно, вам понадобится создать несколько DTO/проекций для одного и того же объекта JPA для разных ресурсов, в которых объект может быть представлен по-разному.
Кроме того, в моем опыте использование аннотаций типа @JsonIgnore
и @JsonIdentityInfo
для объектов JPA точно не предоставляет более удобные представления ресурсов. Вы можете столкнуться с трудностями при объединении объектов обратно в контекст персистентности (из-за игнорируемых свойств), или ваши клиенты могут не иметь возможности потреблять представления ресурсов, поскольку ссылки на объекты как схемы могут быть не поняты. У большинства клиентов JavaScript обычно возникают проблемы с использованием ссылок на объекты, созданных аннотацией @JsonIdentityInfo
, из-за отсутствия здесь стандартизации.
Существуют и другие дополнительные аспекты, которые были бы возможны с помощью DTOs/projections. JPA @EmbeddedId
не вписываются естественным образом в представления ресурсов REST. Некоторые защитники используют аннотацию JAX-RS @MatrixParam
для уникального определения ресурса в URI ресурсов, но это не работает для большинства клиентов. Матричные параметры - это, в конце концов, только примечание к дизайну, а не стандарт (пока). С DTO/проекцией вы можете отображать представление ресурса по вычисленному идентификатору (может быть комбинация составляющих ключей).
Примечание. В настоящее время я работаю над плагином JBoss Forge для REST, где существуют некоторые или все эти проблемы, и будет исправлена в некоторых будущих выпусках через генерацию DTO.
Ответ 2
Я согласен с другими ответами, что DTO - это путь. Они решают много проблем:
-
Разделение слоев и чистый код. В один прекрасный день вам может потребоваться выставить модель данных с использованием другого формата (например, XML) или интерфейса (например, не на основе веб-сервиса). Сохранение всей конфигурации (например, @JsonIgnore
, @JsonidentityInfo
) для каждого интерфейса/формата в модели домена сделало бы действительно беспорядочным. DTO разделяют проблемы. Они могут содержать всю конфигурацию, требуемую вашим внешним интерфейсом (веб-службой), без внесения изменений в модель домена, которая может оставаться агрегированной для веб-службы и формата.
-
Безопасность - вы легко контролируете то, что подвергается клиенту, и то, что клиенту разрешено изменять.
-
Производительность - вы легко контролируете, что отправляется клиенту.
-
Проблемы, такие как (круговые) ссылки на объекты, лениво загружаемые коллекции, также решаются явным и сознательным образом при конвертации в DTO.
Ответ 3
Учитывая ваши ограничения, похоже, нет другого решения, кроме Data Transfer Objects - да, это происходит достаточно часто, чтобы люди назвали этот шаблон...
Ответ 4
Если приложение полностью CRUDish, тогда путь к работе определенно Spring Data REST, в котором вам абсолютно не нужны DTO. Если это будет сложнее, вы будете более безопасными с DTO, обеспечивающими уровень приложения. Но не пытайтесь инкапсулировать DTO внутри слоя контроллера. Они относятся к служебному слою, потому что отображение также является частью логики (что вы впустили в приложение и что вы выпустили из него). Таким образом, прикладной уровень остается герметичным. Конечно, в большинстве случаев это может быть сочетание этих двух.