График объектов Java -> xml, когда необходимо изменить направление ассоциации объектов

Java-приложение, над которым я работаю, имеет объекты с отношениями, подобными приведенным ниже. В реальном приложении оба объекта являются объектами JPA.


class Underlying{}

class Thing
{
  private Underlying underlying;

  public Underlying getUnderlying()
  {
    return underlying;
  }

  public void setUnderlying(final Underlying underlying)
  {
    this.underlying = underlying;
  }
}

В приложении есть требование создать xml вида:

<template>
     <underlying>
        <thing/>
        <thing/>
        <thing/>
     </underlying>
</template>

Таким образом, у нас есть ситуация, когда граф объектов выражает отношение между Вещью и Базовым в направлении, противоположном тому, как это выражено в xml.

Я ожидаю использовать JAXB для создания xml, но в идеале я не хочу создавать новую иерархию объектов для отражения ассоциаций в xml. Есть ли способ создать xml формы, требуемой от сущностей в их текущей форме (с помощью аннотаций xml или чего-то еще)? У меня нет никакого опыта использования JAXB, но из проведенного мной ограниченного исследования не похоже, что можно каким-либо простым способом изменить направление ассоциации. Любая помощь/совет будет принята с благодарностью. Еще один предложенный вариант — использовать XLST для преобразования xml в правильный формат. Я еще не проводил исследований по этой теме, но я добавлю к вопросу, когда у меня будет больше информации.

Спасибо,

Мэтт.


person Matthew Gretton    schedule 10.01.2011    source источник
comment
@Sigmoidal: если вам нужно решение XSLT, вам нужно опубликовать входной образец и желаемый результат, иначе вопрос не будет четко определен для XSLT. Повторная пометка   -  person    schedule 10.01.2011
comment
@Alejandro хорошо, его ввод будет шаблоном элемента {элементная вещь {элемент, лежащий в основе+ }*}, а его вывод будет: шаблон элемента {элемент, лежащий в основе {элементная вещь* }*}   -  person David Bullock    schedule 10.01.2011
comment
@Sigmoidal вы захотите рассмотреть вариант использования для выражения дерева, сгруппированного по <underlying/>. Имеет ли иногда смысл для вашего приложения работать с данными таким образом? Возможно, стоит попробовать альтернативную структуру данных. Если это не работает для вашего приложения, действительно ли внешний формат XML имеет смысл для другого приложения? Возможно, стоит поспорить. Насколько большой график?   -  person David Bullock    schedule 10.01.2011
comment
@Sigmoidal, ты будешь читать инопланетный формат или просто напишешь?   -  person David Bullock    schedule 10.01.2011
comment
@David Bullock: Привет, Дэвид, спасибо за ответ. К сожалению, пока нельзя изменить хотя бы внешний формат XML. Что касается размера графа, существует ~ 1000 базовых элементов, каждый из которых связан с ~ 50 вещами. Или, если посмотреть на это с другой стороны, ~50 000 вещей, каждая из которых связана с одной из ~1000 базовых вещей.   -  person Matthew Gretton    schedule 10.01.2011
comment
@David Bullock: Мы будем читать и писать в инопланетном формате.   -  person Matthew Gretton    schedule 10.01.2011


Ответы (3)


Хитрость заключается в том, чтобы экземпляр Underlying знал о связанных экземплярах Thing. Ниже приведены несколько подходов, которые вы могли бы использовать.

Вариант 1. Сделайте отношения двунаправленными

Проще всего было бы сделать отношения двунаправленными. Затем вы можете использовать расширение @XmlInverseReference в EclipseLink JAXB (MOXy). Примечание: я технический руководитель MOXy:

Вариант 2. Использование XmlAdapter

Вы можете создать адаптированную версию Underlying. При построении адаптированного базового объекта XmlAdapter может запрашивать экземпляры Thing для заполнения свойства Things:

person bdoughan    schedule 10.01.2011
comment
@Blaise Doughan: это довольно крутая вещь, которая улучшила мои знания и уважение к JAXB. Однако можно ли использовать эти стратегии для выполнения требования группировать выходные данные <underlying/>? - person David Bullock; 10.01.2011
comment
@David Bullock: я предполагаю, что базовый элемент соответствует экземпляру базового. Если да, то сгруппировать по не проблема (принимается допущение из двух предложенных вариантов). С другой стороны, если Underlying соответствует Template, можно использовать аннотацию XmlElementWrapper: bdoughan.blogspot.com/2010/09/jaxb-collection-properties.html - person bdoughan; 10.01.2011
comment
@Blaise Doughan: Спасибо за ответ. Параметр адаптера Xml выглядит интересно, но все равно означает, что мне придется создать новую иерархию объектов для сопоставления. Я действительно не хочу, чтобы базовые компоненты знали о вещах, поэтому подход двунаправленного отображения не идеален, но кажется, что это был бы единственный способ повторно использовать текущую иерархию объектов. Спасибо за совет, есть над чем подумать. - person Matthew Gretton; 10.01.2011
comment
@Sigmoidal - вам не потребуется совершенно новая иерархия, только класс AdaptedUnderlying. XmlAdapter преобразует этот класс в/из базового. - person bdoughan; 10.01.2011
comment
@Blaise Doughan: Извините, я изо всех сил пытаюсь понять это. Thing имеет только один Underlying, но Underlying может применяться ко многим Thing. Итак, мы отдаем наш Template для сортировки, и JAXB перебирает все экземпляры Thing. В каждом случае он извлекает файл Underlying. Но мы не можем просто создать <underlying> с <thing> внутри него. Нет, нам нужно подождать, пока он прочитает ВСЮ модель, когда он будет знать для каждого <underlying/>, какие именно <thing/> он содержит. Я не понимаю, как здесь помогает XmlAdapter. В аннотации MOXy @XmlInverstReference также нет примера для 1:many. - person David Bullock; 10.01.2011
comment
@David Bullock - @XmlInverseReference требует, чтобы в объектную модель были внесены изменения, чтобы дать базовому набору Thing. @XmlInverseReference может заполнить двунаправленную связь во время демаршалирования. XmlAdapter потребует создания класса AdaptedUnderlying со свойством типа List‹Thing›. Поскольку используется JPA, XmlAdapter может запросить экземпляры Thing, которые ссылаются на Underlying, и использовать результат для заполнения свойства списка. - person bdoughan; 10.01.2011
comment
@Blaise Doughan: Присмотревшись немного ближе к решению адаптера XML, я понял, что мой комментарий «новая иерархия объектов» был неправильным. Я обязательно попробую. У меня должно быть время в течение следующих нескольких дней. Я дам вам знать, как это происходит. - person Matthew Gretton; 12.01.2011

JAXB может не подойти в вашем случае. JAXB лучше всего подходит, когда вам нужно выполнить возврат из объектной модели в XML и обратно, и у вас есть некоторая свобода действий как с XML, так и с объектной моделью. В этом случае у вас, похоже, нет широты. Никакого JAXB для вас, ИМХО.

Это тоже нетривиальное количество XML-элементов, учитывая, что вы будете где-то их сортировать. Возможно, слишком дорого иметь весь граф и отсортированную копию в памяти? Таким образом, вы захотите получить Thing из хранилища данных JPA, заказанного Underlying (пусть база данных сделает сортировку), и передать их в javax.xml.stream.XMLStreamWriter для вывода.

На стороне ввода используйте javax.xml.stream.XMLStreamReader.

person David Bullock    schedule 10.01.2011
comment
@Sigmoidal Я думаю, что это твой лучший выбор. Подход JAXB требует сортировки в памяти либо для преобразования графа в модель, подходящую для ввода/вывода, до его сериализации в XML, либо после сериализации в XML (с помощью XSLT или путем замены ваших собственных реализаций XMLStreamReader/Writer при упорядочивании/упорядочивании XML с помощью JAXB). Этот подход не требует, чтобы все состояние объектной модели было в памяти дважды. - person David Bullock; 10.01.2011

Борясь с подобной проблемой, я просто наткнулся на дополнительную возможность:

  • Добавьте свойство родительской ссылки в ваши аннотированные классы JAXB.
  • Аннотируйте свойство с помощью @XmlTransient
  • Реализовать метод public void afterUnmarshal(Unmarshaller u, Object parent)
  • Реализуйте логику для установки родительского указателя в этом методе следующим образом: this.parent= (ParentType) parent; Конечно, в этом методе можно добавить больше вещей.

Метод вызывается JAXB после десортировки, как следует из названия.

Ссылки: (довольно старое) обсуждение на forums.java.net, Руководство по JAXB

Я не могу использовать @XmlInverseReference, поскольку мы используем реализацию JAXB, отличную от MOXy. Хотя я и оценил @XmlAdapter, я считаю этот подход более простым, поскольку он не требует дополнительных классов.

Хотя это не полностью соответствует описанию вашей проблемы, я все же думаю, что это может помочь будущим читателям.

person wwerner    schedule 01.02.2011