Як створити метамодель об'єкта JPA?


94

У дусі безпеки типу, пов'язаної з CriteriaQuery JPA 2.0, також є API для підтримки метамоделі представлення .

Хтось знає про повністю функціональну реалізацію цього API (для створення метамоделі на відміну від створення класів метамоделі вручну)? Було б дивовижно, якби хтось також знав кроки для встановлення цього налаштування в Eclipse (я припускаю, це так просто, як налаштувати процесор анотацій, але ви ніколи не знаєте).

EDIT: Щойно натрапив на генератор метамоделей Hibernate JPA 2 . Але проблема залишається, оскільки я не можу знайти посилання для завантаження банки.

EDIT 2: Тим часом минуло відтоді, як я задав це питання, але я подумав, що повернусь і додам посилання на проект Hibernate JPA Model Generator на SourceForge

Відповіді:


87

Було б дивним, якби хтось також знав кроки для налаштування цього в Eclipse (я вважаю, це так просто, як налаштувати процесор анотацій, але ви ніколи не знаєте)

Так. Ось реалізації та інструкції для різних реалізацій JPA 2.0:

EclipseLink

Зимує

OpenJPA

DataNucleus


Остання реалізація режиму глибокого сну доступна на:

Старіший режим сплячого режиму знаходиться за адресою:


1
Посилання DataNucleus мертве.
Карл Ріхтер,

1
Посилання в режимі глибокого сну теж мертве
фрілансер

43

Погляньте, будь ласка, на jpa-метамоделі-з-maven-приклад .

Зимує

  • Нам потрібно 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 для створення моїх речей
Kalpesh Soni

@ymajoros Чи заборонено в ТАК говорити something is recommendedбез IMHO? Я не представляю когось від імені.
Джин Квон

1
BTW, див. Відповідь Сортера для EclipseLink. Це конфігурація, яку я використовую роками, і вона прекрасно працює. stackoverflow.com/questions/3037593 / ...
ymajoros

Це не конкретна реалізація, я намагаюся використовувати метамодель, сгенеровану в режимі зимування, з EclipseLink та отримати NullPointerException
Michał Ziobro

@ymajoros Все ще потрібен persistence.xml, чи не так?
Джин Квон

20

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

  1. Виберіть проект у Провіднику пакунків
  2. Перейдіть у вікно Властивості -> JPA
  3. Виберіть вихідну папку з метанодичної групи Canonical (JPA 2.0)
  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
Jin Kwon

5

Для сплячого як постачальника, який є найпоширенішим IMHO:

У випадку таких інструментів побудови, як Gradle, Maven, вам потрібно мати склянку Hibernate JPA 2 Metamodel Generator на рівні classpath та компілятора> = 1.6, тобто все, що вам потрібно для створення проекту, і метамодель буде створена автоматично.

У випадку IDE Eclipse 1. перейдіть до Project-> Properties-> Java Compiler-> Annotation Processing та увімкніть його. 2. Розгорніть обробку анотацій-> Фабричний шлях-> Додати зовнішню банку, додайте Hibernate JPA 2 Metamodel Generator jar, перевірте нещодавно додану банку та скажіть «ОК». Очищення та побудова зроблено!

Посилання Hibernate JPA 2 Metamodel Generator jar посилання від maven repo 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?
Мелькор

незважаючи на те, що сплячка-jpamodelgen була додана в пам’яті, я повинен був зробити це, і це спрацювало
Фрілансер

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лінійку String при створенні Joinекземпляра, і ми використовували titleліній String при посиланні на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. Перегляньте цю статтю, щоб отримати докладніші відомості про плагін IDE Codota.

Або, скажімо , ми хочемо принести проекцію 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>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.