如何生成JPA实体元模型?

115

为了符合与CriteriaQuery相关的类型安全精神,JPA 2.0还有一个API来支持实体的元模型表示。

是否有人知道这个API的完整功能实现(生成元模型而不是手动创建元模型类)?如果有人知道在Eclipse中设置这些步骤也会很棒(我假设它和设置注释处理器一样简单,但你永远不知道)。

编辑: 刚刚发现了Hibernate JPA 2 Metamodel Generator 。但问题仍然存在,因为我找不到任何下载链接。

编辑2: 自从我问这个问题以来已经过了一段时间,但我想回来添加一个链接到SourceForge上的Hibernate JPA Model Generator项目

9个回答

91

如果有人知道在Eclipse中设置这个的步骤就更好了(我猜应该和设置注解处理器一样简单,但你永远不知道)

是的,没错。以下是各种JPA 2.0实现的实现方法和说明:

EclipseLink

Hibernate

OpenJPA

DataNucleus


最新的Hibernate实现方法可以在以下网址找到:


1
DataNucleus的链接已失效。 - Kalle Richter
1
Hibernate的链接也失效了。 - Derrick

53

请查看jpa-metamodels-with-maven-example

Hibernate

  • 我们需要org.hibernate.org:hibernate-jpamodelgen
  • 处理器类是org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor

Hibernate作为依赖项

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

作为处理器的Hibernate

      <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

  • We need org.apache.openjpa:openjpa.
  • The processor class is org.apache.openjpa.persistence.meta.AnnotationProcessor6.
  • OpenJPA seems require additional element <openjpa.metamodel>true</openjpa.metamodel>.

OpenJPA as a dependency

  <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
请明确,即使您使用Hibernate生成,生成的内容仍可与EclipseLink一起使用。我无法从NetBeans 8生成元模型,不得不创建一个Maven测试项目来生成我的内容。 - Kalpesh Soni
@ymajoros 在SO上说“某事被推荐”而不加上“在我看来”是被禁止的吗?我并不代表任何其他人。 - Jin Kwon
1
顺便提一下,可以看看Sorter在EclipseLink中的答案。这是我多年来一直在使用的配置,它完美地运行着。https://dev59.com/snA75IYBdhLWcg3w6Nn8#11245730 - ymajoros
这个实现不是特定于Hibernate吗?我试图在EclipseLink中使用Hibernate生成的元模型,但是出现了NullPointerException。 - Michał Ziobro
1
也许值得一提的是,对于使用Java11的hibernate-jpamodelgen,maven-processor-plugin至少应该是4.0-rc版本。请参见https://stackoverflow.com/a/61305429/5911964。 - absence
显示剩余4条评论

23

Eclipse的JPA 2.0支持通过Dali(包含在“Eclipse IDE for JEE Developers”中)具有与Eclipse集成的元模型生成器。

  1. Package Explorer中选择您的项目
  2. 转到Properties -> JPA对话框
  3. Canonical metamodel (JPA 2.0)组中选择源文件夹
  4. 单击Apply按钮以在所选源文件夹中生成元模型类

enter image description here

这适用于任何JPA提供程序,因为生成的类是标准的。

另请参见此处


有没有什么方法可以自己启动该进程?这对我来说并不可靠地产生元模型。 - thatsIch

19

假设我们的应用程序使用以下实体:PostPostCommentPostDetailsTag,它们形成了一对多、一对一和多对多表关系:

JPA Criteria Metamodel

如何生成JPA Criteria元模型

Hibernate ORM提供的hibernate-jpamodelgen工具可用于扫描项目实体并生成JPA Criteria元模型。只需在Maven pom.xml配置文件中的maven-compiler-plugin中添加以下annotationProcessorPath即可:

<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_元模型类是这样生成的:

@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用于基本的idname Tag JPA实体属性。

文章实体元模型

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实体具有两个基本属性idtitle,一个一对多的comments集合,一个一对一的details关联,以及一个多对多的tags集合。

Post_元模型类生成如下:

@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";
}
SingularAttribute表示基本的idtitle属性以及一对一的details关联,而JPA ListAttribute表示commentstags集合。 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
}

所有实体属性都将由关联的 PostDetails_ 元模型类中的 JPA SingularAttribute 表示:

@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
}

此外,所有实体属性都由关联的PostComments_元模型类中的JPA SingularAttribute表示:

@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 Criteria元模型

如果没有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();

注意我们创建Join实例时使用了post字符串,引用Post title时使用了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();

或者,假设我们想在过滤PosttitlePostDetailscreatedOn属性时获取DTO投影。

我们可以在创建联接属性时使用元模型,以及在构建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();

很酷,对吧?


8
对于EclipseLink,只需要以下依赖项即可生成元模型。不需要其他任何东西。
    <dependency>
        <groupId>org.eclipse.persistence</groupId>
        <artifactId>org.eclipse.persistence.jpa.modelgen.processor</artifactId>
        <version>2.5.1</version>
        <scope>provided</scope>
    </dependency>

非常重要的提示:仅当实体在持久性单元中声明时,元模型才会生成。它不适用于发现的实体。 - Bart Weber
@Barthelomeus 您的注释是错误的。EclipseLink 2.5.1+ 将为未列出的实体生成元模型类,只需在 persisetence.xml 中指定 <exclude-unlisted-classes>false</exclude-unlisted-classes> 即可。 - Michele Mariotti
请注意,如果没有persistence.xml,EclipseLink将无法生成。 - Jin Kwon

6

对于我个人而言,最常见的提供程序是Hibernate:

如果你使用构建工具如Gradle、Maven等,那么你需要在类路径中拥有Hibernate JPA 2 Metamodel Generator jar,同时编译器级别>=1.6,这样就可以构建项目并自动生成元模型。

如果你使用Eclipse IDE: 1. 转到Project->Properties->Java Compiler->Annotation Processing并启用它。 2. 展开Annotation Processing->Factory Path->Add External Jar添加Hibernate JPA 2 Metamodel Generator jar,检查新添加的jar并点击OK。完成清理和构建!

从Maven仓库链接Hibernate JPA 2 Metamodel Generator jar: 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文件中即可。 - Ilya Serbis
在使用Maven和Eclipse时,我是否需要同时进行配置? - Melkor
尽管在pom中添加了hibernate-jpamodelgen,但我还是不得不这样做,而且它起作用了。 - Derrick
这也应该是被接受的答案。非常感谢,Sandeep。 - Shubham Arya

1

根据我在这里阅读的内容,我用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>

0

请参考此帖子,了解如何在IDE中使用Maven进行最小配置以及处理生成的JPA元模型源代码。


0

使用Eclipse和Hibernate:

  1. 进入菜单项目 > 属性 > 项目结构;
  2. 启用JPA 2.1版本。它将启用一个新的菜单JPA。
  3. 在菜单JPA中,在平台字段中选择“Hibernate(JPA 2.x)”,在JPA实现字段中选择“禁用库配置”,在规范元模型字段中选择“src/main/java”。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接