EclipseLink — JPA и MOXy — разные представления одной и той же модели данных

вот это вызов...

У меня есть сложная распределенная система, основанная на той же модели

Это выглядит так:

A <-(XML)-> B <-(JSON)-> C

A, B и C — это разные приложения, в основном основанные на одной и той же модели, поэтому я решил сохранить модель в отдельном проекте Java (Maven).

  • Каждое приложение использует JPA для сохранения
  • Каждое приложение использует и сохраняет только часть атрибутов сущностей.
  • Формат обмена данными основан на той же модели (XML или JSON с MOXy).
  • Существует два формата обмена, в которых используется только часть атрибутов сущностей.

Вот более технический пример объекта (псевдокод):

class Foo {
  a;
  ab;
  bc;
  c;
  ac;
  // ...
}

где a используется приложением A, ab используется приложением A и приложением B, bc используется приложением B и C и т. д.

Такое же требование к формату обмена.

У вас есть идеи, как это реализовать?

С наилучшими пожеланиями.

Изменить: вероятно, лучшим решением этой проблемы является автоматическое создание различных классов из глобальной модели. Взяв Entity из приведенного выше примера, это будет выглядеть так:

Приложение А:

class Foo {
  a;
  ab;
  ac;
  // ...
}

Приложение Б:

class Foo {
  ab;
  bc;
  // ...
}

person kalamar    schedule 08.05.2013    source источник


Ответы (2)


Если вы используете EclipseLink 2.5.0, вы можете использовать расширение MOXy @XmlNamedObjectGraphs для этого варианта использования. Кандидат на выпуск EclipseLink 2.5.0 можно загрузить по следующей ссылке:

Модель домена (Foo)

Расширение @XmlNamedObjectGraph позволяет вам указать подмножества ваших отображений, которые можно использовать с маршаллингом и демаршаллингом.

import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.*;

@XmlNamedObjectGraphs({ 
    @XmlNamedObjectGraph(
        name="a",
        attributeNodes={
            @XmlNamedAttributeNode("a"),
            @XmlNamedAttributeNode("ab"),
            @XmlNamedAttributeNode("ac")
        }
    ),
    @XmlNamedObjectGraph(
        name="b",
        attributeNodes={
            @XmlNamedAttributeNode("ab"),
            @XmlNamedAttributeNode("bc")
        }
    ),
    @XmlNamedObjectGraph(
        name="c",
        attributeNodes={
            @XmlNamedAttributeNode("bc"),
            @XmlNamedAttributeNode("c"),
            @XmlNamedAttributeNode("ac")
        }
    )

})
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Foo {

    int a;
    int ab;
    int bc;
    int c;
    int ac;

}

Демо

В приведенном ниже демонстрационном коде мы заполним один экземпляр Foo, а затем выведем его четырьмя различными способами, используя определенные нами графы объектов.

import javax.xml.bind.*;
import org.eclipse.persistence.jaxb.MarshallerProperties;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Foo.class);
        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

        Foo foo = new Foo();
        foo.a = 1;
        foo.ab = 2;
        foo.ac = 3;
        foo.bc = 4;
        foo.c = 5;

        // Marshal to XML - Everything
        marshaller.marshal(foo, System.out);

        // Marshal to XML - Application A
        marshaller.setProperty(MarshallerProperties.OBJECT_GRAPH, "a");
        marshaller.marshal(foo, System.out);

        // Marshal to JSON - Application B
        marshaller.setProperty(MarshallerProperties.MEDIA_TYPE, "application/json");
        marshaller.setProperty(MarshallerProperties.OBJECT_GRAPH, "b");
        marshaller.marshal(foo, System.out);

        // Marshal to JSON - Application C
        marshaller.setProperty(MarshallerProperties.OBJECT_GRAPH, "c");
        marshaller.marshal(foo, System.out);
    }

}

Вывод

Ниже приведены четыре разных вида, которые мы создали из нашего демо-кода. Помните, что каждый раз мы упорядочивали один и тот же экземпляр Foo с одними и теми же заполненными данными.

<?xml version="1.0" encoding="UTF-8"?>
<foo>
   <a>1</a>
   <ab>2</ab>
   <bc>4</bc>
   <c>5</c>
   <ac>3</ac>
</foo>
<?xml version="1.0" encoding="UTF-8"?>
<foo>
   <a>1</a>
   <ab>2</ab>
   <ac>3</ac>
</foo>
{
   "foo" : {
      "ab" : 2,
      "bc" : 4
   }
}{
   "foo" : {
      "bc" : 4,
      "c" : 5,
      "ac" : 3
   }
}

Для получения дополнительной информации

person bdoughan    schedule 08.05.2013
comment
Привет, Блейз Доган, спасибо... это расширение, которое я ищу. Это очень полезно, когда вам все равно нужно писать на стороне клиента (веб-приложение, Android, ...). Но если вы хотите оставить Java и MOXy на стороне клиента (вы привели примеры для сортировки, но не для демаршаллинга), было бы неплохо автоматически генерировать классы сущностей клиентов из аннотаций. В противном случае у вас есть некоторые нулевые свойства... модель несовместима. На мой взгляд, единственным решением является автогенерация кода для клиента (на стороне несортировки). Есть ли шанс получить эту функцию в следующем выпуске? - person kalamar; 10.05.2013
comment
А как насчет материалов JPA? На мой взгляд, спецификация JAXB (в данном случае это просто расширение EclipseLink, но в любом случае) должна работать вместе со спецификацией JPA. Как вы думаете? - person kalamar; 10.05.2013
comment
@kalamar - Unmarshalling работает так же, вы просто устанавливаете свойство для Unmarshaller вместо Marshaller. Я мог представить, как мы добавим функцию, позволяющую генерировать схему на основе графа объектов, а затем генерировать на ее основе модель. В JPA 2.1 графы именованных объектов работают почти так же, как графы именованных объектов MOXy. Все, что мы добавляем в EclipseLink MOXy, совместимо с JPA, поскольку EclipseLink также является поставщиком JPA. - person bdoughan; 10.05.2013

Если модели очень разные, то, возможно, они просто имеют разные модели или, возможно, используют наследование.

Для JPA вы можете определить сопоставления в orm.xml и выбрать отображение того, что вы хотите, поэтому вы можете использовать одну и ту же модель, просто имея разные orm.xml для каждого приложения.

person James    schedule 08.05.2013
comment
Привет, спасибо за ответ. Я это уже обдумал. Проблема здесь в том, что когда A -(marshall)-(XML)-(unmarshall)-> B вам все еще нужно использовать полную модель в приложении B. Я имею в виду, что у вас все еще есть те же классы объектов в приложении B. Это означает, что у вас есть некоторые неиспользуемые свойства. или отношения. Я думаю, что единственным решением для этого является создание пользовательского кода (файлы *.java) из глобальной модели на основе некоторых самописных аннотаций @ViewModel (работа в процессе). Спасибо в любом случае. - person kalamar; 08.05.2013