Как создать метамодель объекта JPA?

97

В духе безопасности типов, связанной с CriteriaQuery, JPA 2.0 также имеет API для поддержки представления сущностей в метамодели .

Кто-нибудь знает о полностью функциональной реализации этого API (для создания метамодели, а не создания классов метамодели вручную)? Было бы здорово, если бы кто-то также знал, как это настроить в Eclipse (я предполагаю, что это так же просто, как настроить процессор аннотаций, но вы никогда не знаете).

РЕДАКТИРОВАТЬ: только что наткнулся на генератор метамодели Hibernate JPA 2 . Но проблема остается, так как я не могу найти ссылок для скачивания jar.

РЕДАКТИРОВАТЬ 2: Прошло некоторое время с тех пор, как я задал этот вопрос, но я подумал, что вернусь и добавлю ссылку на проект Hibernate JPA Model Generator на SourceForge

Андрей
источник

Ответы:

88

Было бы здорово, если бы кто-то также знал, как это настроить в Eclipse (я предполагаю, что это так же просто, как настройка процессора аннотаций, но вы никогда не знаете)

Да, это. Вот реализации и инструкции для различных реализаций JPA 2.0:

EclipseLink

Спящий режим

OpenJPA

DataNucleus


Последняя реализация Hibernate доступна по адресу:

Более старая реализация Hibernate находится по адресу:

Паскаль Тивент
источник
1
Ссылка DataNucleus мертва.
Карл Рихтер
1
Ссылка Hibernate тоже не работает
Freelancer
43

Пожалуйста, взгляните на jpa-metamodels-with-maven-example .

Спящий режим

  • Нам нужно org.hibernate.org:hibernate-jpamodelgen.
  • Класс процессора org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor.

Гибернация как зависимость

    <dependency>
      <groupId>org.hibernate.orm</groupId>
      <artifactId>hibernate-jpamodelgen</artifactId>
      <version>${version.hibernate-jpamodelgen}</version>
      <scope>provided</scope>
    </dependency>

Гибернация как процессор

      <plugin>
        <groupId>org.bsc.maven</groupId>
        <artifactId>maven-processor-plugin</artifactId>
        <executions>
          <execution>
            <goals>
              <goal>process</goal>
            </goals>
            <phase>generate-sources</phase>
            <configuration>
              <compilerArguments>-AaddGeneratedAnnotation=false</compilerArguments> <!-- suppress java.annotation -->
              <processors>
                <processor>org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor</processor>
              </processors>
            </configuration>
          </execution>
        </executions>
        <dependencies>
          <dependency>
            <groupId>org.hibernate.orm</groupId>
            <artifactId>hibernate-jpamodelgen</artifactId>
            <version>${version.hibernate-jpamodelgen}</version>
          </dependency>
        </dependencies>
      </plugin>

OpenJPA

  • Нам нужно org.apache.openjpa:openjpa.
  • Класс процессора org.apache.openjpa.persistence.meta.AnnotationProcessor6.
  • OpenJPA, похоже, требует дополнительного элемента <openjpa.metamodel>true<openjpa.metamodel>.

OpenJPA как зависимость

  <dependencies>
    <dependency>
      <groupId>org.apache.openjpa</groupId>
      <artifactId>openjpa</artifactId>
      <scope>provided</scope>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <compilerArgs>
            <arg>-Aopenjpa.metamodel=true</arg>
          </compilerArgs>
        </configuration>
      </plugin>
    </plugins>
  </build>

OpenJPA как процессор

      <plugin>
        <groupId>org.bsc.maven</groupId>
        <artifactId>maven-processor-plugin</artifactId>
        <executions>
          <execution>
            <id>process</id>
            <goals>
              <goal>process</goal>
            </goals>
            <phase>generate-sources</phase>
            <configuration>
              <processors>
                <processor>org.apache.openjpa.persistence.meta.AnnotationProcessor6</processor>
              </processors>
              <optionMap>
                <openjpa.metamodel>true</openjpa.metamodel>
              </optionMap>
            </configuration>
          </execution>
        </executions>
        <dependencies>
          <dependency>
            <groupId>org.apache.openjpa</groupId>
            <artifactId>openjpa</artifactId>
            <version>${version.openjpa}</version>
          </dependency>
        </dependencies>
      </plugin>

EclipseLink

  • Нам нужно org.eclipse.persistence:org.eclipse.persistence.jpa.modelgen.processor.
  • Класс процессора org.eclipse.persistence.internal.jpa.modelgen.CanonicalModelProcessor.
  • EclipseLink требует persistence.xml.

EclipseLink как зависимость

  <dependencies>
    <dependency>
      <groupId>org.eclipse.persistence</groupId>
      <artifactId>org.eclipse.persistence.jpa.modelgen.processor</artifactId>
      <scope>provided</scope>
    </dependency>

EclipseLink как процессор

    <plugins>
      <plugin>
        <groupId>org.bsc.maven</groupId>
        <artifactId>maven-processor-plugin</artifactId>
        <executions>
          <execution>
            <goals>
              <goal>process</goal>
            </goals>
            <phase>generate-sources</phase>
            <configuration>
              <processors>
                <processor>org.eclipse.persistence.internal.jpa.modelgen.CanonicalModelProcessor</processor>
              </processors>
              <compilerArguments>-Aeclipselink.persistencexml=src/main/resources-${environment.id}/META-INF/persistence.xml</compilerArguments>
            </configuration>
          </execution>
        </executions>
        <dependencies>
          <dependency>
            <groupId>org.eclipse.persistence</groupId>
            <artifactId>org.eclipse.persistence.jpa.modelgen.processor</artifactId>
            <version>${version.eclipselink}</version>
          </dependency>
        </dependencies>
      </plugin>

DataNucleus

  • Нам нужно org.datanucleus:datanucleus-jpa-query.
  • Класс процессора org.datanucleus.jpa.query.JPACriteriaProcessor.

DataNucleus как зависимость

  <dependencies>
    <dependency>
      <groupId>org.datanucleus</groupId>
      <artifactId>datanucleus-jpa-query</artifactId>
      <scope>provided</scope>
    </dependency>
  </dependencies>

DataNucleus как процессор

      <plugin>
        <groupId>org.bsc.maven</groupId>
        <artifactId>maven-processor-plugin</artifactId>
        <executions>
          <execution>
            <id>process</id>
            <goals>
              <goal>process</goal>
            </goals>
            <phase>generate-sources</phase>
            <configuration>
              <processors>
                <processor>org.datanucleus.jpa.query.JPACriteriaProcessor</processor>
              </processors>
            </configuration>
          </execution>
        </executions>
        <dependencies>
          <dependency>
            <groupId>org.datanucleus</groupId>
            <artifactId>datanucleus-jpa-query</artifactId>
            <version>${version.datanucleus}</version>
          </dependency>
        </dependencies>
      </plugin>
Джин Квон
источник
3
Чтобы быть ясным, сгенерированный материал можно использовать с eclipselink, даже если вы используете спящий режим для его генерации, я не смог сгенерировать метамодель из netbeans 8, и мне пришлось создать тестовый проект maven для генерации моих материалов
Калпеш Сони
@ymajoros В SO нельзя говорить something is recommendedбез IMHO? Я не представляю интересы кого-либо еще.
Джин Квон
1
Кстати, см. Ответ Sorter для EclipseLink. Это конфигурация, которую я использую в течение многих лет, и она отлично работает. stackoverflow.com/questions/3037593/…
ymajoros 02
Разве эта реализация не специфична? Я пытаюсь использовать сгенерированную Hibernate метамодель с EclipseLink и получить
исключение
@ymajoros Все еще нужен persistence.xml, не так ли?
Джин Квон
20

Поддержка Eclipse JPA 2.0 через Dali (которая включена в «Eclipse IDE для разработчиков JEE») имеет собственный генератор метамоделей, интегрированный с Eclipse.

  1. Выберите свой проект в проводнике пакетов
  2. Перейдите в Свойства -> диалоговое окно JPA.
  3. Выберите папку источника из канонической метамодели (2,0 JPA) группы
  4. Нажмите кнопку Применить , чтобы сгенерировать классы метамодели в выбранной исходной папке.

введите описание изображения здесь

Это должно работать с любым провайдером JPA, поскольку сгенерированные классы являются стандартными.

Также смотрите здесь .

Джеймс
источник
Есть ли способ самому начать процесс? Это не дает надежной метамодели для меня
это
6

Для eclipselink для создания метамодели достаточно только следующей зависимости. Больше ничего не нужно.

    <dependency>
        <groupId>org.eclipse.persistence</groupId>
        <artifactId>org.eclipse.persistence.jpa.modelgen.processor</artifactId>
        <version>2.5.1</version>
        <scope>provided</scope>
    </dependency>
Сортировщик
источник
@Barthelomeus, твоя заметка - ложь . EclipseLink 2.5.1+ также будет генерировать классы метамодели для объектов, не включенных в список, просто укажите <exclude-unlisted-classes>false</exclude-unlisted-classes>в persisetence.xml
Мишель Мариотти,
Обратите внимание, что eclipselink не будет генерироваться безpersistence.xml
Джин Квон
6

Для Hibernate в качестве провайдера, который является наиболее распространенным IMHO:

В случае инструментов сборки, таких как Gradle, Maven, вам необходимо иметь банку генератора метамодели Hibernate JPA 2 в пути к классам и на уровне компилятора> = 1.6, это все, что вам нужно для сборки проекта, и метамодель будет сгенерирована автоматически.

В случае IDE Eclipse 1. перейдите в Project-> Properties-> Java Compiler-> Annotation Processing и включите его. 2. Разверните Обработка аннотаций-> Заводской путь-> Добавить внешний файл Jar, добавьте файл Hibernate JPA 2 Metamodel Generator jar, проверьте только что добавленный файл jar и скажите ОК. Очистка и сборка завершена!

Link Hibernate JPA 2 Metamodel Generator jar ссылка из репозитория maven https://mvnrepository.com/artifact/org.hibernate/hibernate-jpamodelgen

СандипГодара
источник
В моем случае <dependencies> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-jpamodelgen</artifactId> <scope>compile</scope> </dependency> </dependencies>было достаточно добавления в pom.xml.
Lu55
Нужны ли мне обе конфигурации при использовании maven и Eclipse?
Мелькор
хотя hibernate-jpamodelgen был добавлен в pom, мне пришлось это сделать, и это сработало
Freelancer
Это тоже должен быть принятый ответ. Большое спасибо, Сандип
Шубхам Арья
3

Поскольку это очень частый вопрос, я написал эту статью , на которой основан этот ответ.

Давайте предположим , наше приложение использует следующее Post, PostComment, PostDetailsи Tagобъекты, которые образуют один-ко-многим, один-к-одному и многие-ко-многим отношений таблицы :

Метамодель критериев JPA

Как создать метамодель критериев JPA

hibernate-jpamodelgenИнструмент , предоставляемый Hibernate ORM может быть использован для сканирования объектов проекта и создания JPA Критерии метамодели. Все , что вам нужно сделать , это добавить следующее annotationProcessorPathк maven-compiler-pluginв Maven pom.xmlконфигурационном файле:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>${maven-compiler-plugin.version}</version>
    <configuration>
        <annotationProcessorPaths>
            <annotationProcessorPath>
                <groupId>org.hibernate</groupId>
                <artifactId>hibernate-jpamodelgen</artifactId>
                <version>${hibernate.version}</version>
            </annotationProcessorPath>
        </annotationProcessorPaths>
    </configuration>
</plugin>

Теперь, когда проект скомпилирован, вы можете увидеть, что в targetпапке генерируются следующие классы Java:

> tree target/generated-sources/
target/generated-sources/
└── annotations
    └── com
        └── vladmihalcea
            └── book
                └── hpjp
                    └── hibernate
                        ├── forum
                        │   ├── PostComment_.java
                        │   ├── PostDetails_.java
                        │   ├── Post_.java
                        │   └── Tag_.java

Метамодель объекта тега

Если Tagобъект отображается следующим образом:

@Entity
@Table(name = "tag")
public class Tag {

    @Id
    private Long id;

    private String name;

    //Getters and setters omitted for brevity
}

Класс Tag_Metamodel создается следующим образом:

@Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
@StaticMetamodel(Tag.class)
public abstract class Tag_ {

    public static volatile SingularAttribute<Tag, String> name;
    public static volatile SingularAttribute<Tag, Long> id;

    public static final String NAME = "name";
    public static final String ID = "id";
}

SingularAttributeИспользуется для основных idи name TagJPA атрибутов сущностей.

Метамодель объекта публикации

PostОбъект отображается следующим образом:

@Entity
@Table(name = "post")
public class Post {

    @Id
    private Long id;

    private String title;

    @OneToMany(
        mappedBy = "post",
        cascade = CascadeType.ALL,
        orphanRemoval = true
    )
    private List<PostComment> comments = new ArrayList<>();

    @OneToOne(
        mappedBy = "post",
        cascade = CascadeType.ALL,
        fetch = FetchType.LAZY
    )
    @LazyToOne(LazyToOneOption.NO_PROXY)
    private PostDetails details;

    @ManyToMany
    @JoinTable(
        name = "post_tag",
        joinColumns = @JoinColumn(name = "post_id"),
        inverseJoinColumns = @JoinColumn(name = "tag_id")
    )
    private List<Tag> tags = new ArrayList<>();

    //Getters and setters omitted for brevity
}

PostПредприятие имеет два основных атрибутов, idи title, один-ко-многим commentsколлекции, один-к-одному detailsассоциации, и многие-ко-многим tagsколлекции.

Класс Post_Metamodel создается следующим образом:

@Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
@StaticMetamodel(Post.class)
public abstract class Post_ {

    public static volatile ListAttribute<Post, PostComment> comments;
    public static volatile SingularAttribute<Post, PostDetails> details;
    public static volatile SingularAttribute<Post, Long> id;
    public static volatile SingularAttribute<Post, String> title;
    public static volatile ListAttribute<Post, Tag> tags;

    public static final String COMMENTS = "comments";
    public static final String DETAILS = "details";
    public static final String ID = "id";
    public static final String TITLE = "title";
    public static final String TAGS = "tags";
}

Основной idи titleатрибуты, а также один-к-одному detailsассоциации, которые представлены в SingularAttributeто время как commentsи tagsколлекции представлены JPA ListAttribute.

Метамодель сущности PostDetails

PostDetailsОбъект отображается следующим образом:

@Entity
@Table(name = "post_details")
public class PostDetails {

    @Id
    @GeneratedValue
    private Long id;

    @Column(name = "created_on")
    private Date createdOn;

    @Column(name = "created_by")
    private String createdBy;

    @OneToOne(fetch = FetchType.LAZY)
    @MapsId
    @JoinColumn(name = "id")
    private Post post;

    //Getters and setters omitted for brevity
}

Все атрибуты сущности будут представлены JPA SingularAttributeв связанном PostDetails_классе Metamodel:

@Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
@StaticMetamodel(PostDetails.class)
public abstract class PostDetails_ {

    public static volatile SingularAttribute<PostDetails, Post> post;
    public static volatile SingularAttribute<PostDetails, String> createdBy;
    public static volatile SingularAttribute<PostDetails, Long> id;
    public static volatile SingularAttribute<PostDetails, Date> createdOn;

    public static final String POST = "post";
    public static final String CREATED_BY = "createdBy";
    public static final String ID = "id";
    public static final String CREATED_ON = "createdOn";
}

Метамодель объекта PostComment

PostCommentОтображаются следующим образом :

@Entity
@Table(name = "post_comment")
public class PostComment {

    @Id
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    private Post post;

    private String review;

    //Getters and setters omitted for brevity
}

И все атрибуты сущности представлены JPA SingularAttributeв связанном PostComments_классе Metamodel:

@Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
@StaticMetamodel(PostComment.class)
public abstract class PostComment_ {

    public static volatile SingularAttribute<PostComment, Post> post;
    public static volatile SingularAttribute<PostComment, String> review;
    public static volatile SingularAttribute<PostComment, Long> id;

    public static final String POST = "post";
    public static final String REVIEW = "review";
    public static final String ID = "id";
}

Использование метамодели критериев JPA

Без метамодели JPA запрос API критериев, который должен получать PostCommentобъекты, отфильтрованные по их связанному Postзаголовку, выглядел бы следующим образом:

CriteriaBuilder builder = entityManager.getCriteriaBuilder();

CriteriaQuery<PostComment> query = builder.createQuery(PostComment.class);
Root<PostComment> postComment = query.from(PostComment.class);

Join<PostComment, Post> post = postComment.join("post");

query.where(
    builder.equal(
        post.get("title"),
        "High-Performance Java Persistence"
    )
);

List<PostComment> comments = entityManager
    .createQuery(query)
    .getResultList();

Обратите внимание, что мы использовали postстроковый литерал при создании Joinэкземпляра, и мы использовали titleстроковый литерал при ссылке на Post title.

Метамодель JPA позволяет нам избежать жесткого кодирования атрибутов сущности, как показано в следующем примере:

CriteriaBuilder builder = entityManager.getCriteriaBuilder();

CriteriaQuery<PostComment> query = builder.createQuery(PostComment.class);
Root<PostComment> postComment = query.from(PostComment.class);

Join<PostComment, Post> post = postComment.join(PostComment_.post);

query.where(
    builder.equal(
        post.get(Post_.title),
        "High-Performance Java Persistence"
    )
);

List<PostComment> comments = entityManager
    .createQuery(query)
    .getResultList();

Написание запросов API критериев JPA намного проще, если вы используете инструмент завершения кода, такой как Codota. Проверьте эту статью для более подробной информации о плагине Codota IDE.

Или, скажем , мы хотим принести проекцию DTO во время фильтрации Post titleи на PostDetails createdOnатрибуты.

Мы можем использовать метамодель при создании атрибутов соединения, а также при создании псевдонимов столбцов проекции DTO или при ссылке на атрибуты сущности, которые нам нужно фильтровать:

CriteriaBuilder builder = entityManager.getCriteriaBuilder();

CriteriaQuery<Object[]> query = builder.createQuery(Object[].class);

Root<PostComment> postComment = query.from(PostComment.class);
Join<PostComment, Post> post = postComment.join(PostComment_.post);

query.multiselect(
    postComment.get(PostComment_.id).alias(PostComment_.ID),
    postComment.get(PostComment_.review).alias(PostComment_.REVIEW),
    post.get(Post_.title).alias(Post_.TITLE)
);

query.where(
    builder.and(
        builder.like(
            post.get(Post_.title),
            "%Java Persistence%"
        ),
        builder.equal(
            post.get(Post_.details).get(PostDetails_.CREATED_BY),
            "Vlad Mihalcea"
        )
    )
);

List<PostCommentSummary> comments = entityManager
    .createQuery(query)
    .unwrap(Query.class)
    .setResultTransformer(Transformers.aliasToBean(PostCommentSummary.class))
    .getResultList();

Круто, правда?

Влад Михалча
источник
0

Хорошо, исходя из того, что я здесь прочитал, я сделал это с помощью EclipseLink таким образом, и мне не нужно было помещать зависимость процессора в проект, только как annotationProcessorPathэлемент плагина компилятора.

    <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
            <annotationProcessorPaths>
                <annotationProcessorPath>
                    <groupId>org.eclipse.persistence</groupId>
                    <artifactId>org.eclipse.persistence.jpa.modelgen.processor</artifactId>
                    <version>2.7.7</version>
                </annotationProcessorPath>
            </annotationProcessorPaths>
            <compilerArgs>
                <arg>-Aeclipselink.persistencexml=src/main/resources/META-INF/persistence.xml</arg>
            </compilerArgs>
        </configuration>
    </plugin>
dmatej
источник