Bagaimana cara menghasilkan Metamodel entitas JPA?

94

Dalam semangat keamanan tipe yang terkait dengan CriteriaQuery JPA 2.0 juga memiliki API untuk mendukung representasi Metamodel entitas.

Adakah yang mengetahui implementasi yang berfungsi penuh dari API ini (untuk menghasilkan Metamodel daripada membuat kelas metamodel secara manual)? Akan luar biasa jika seseorang juga mengetahui langkah-langkah untuk menyiapkannya di Eclipse (Saya menganggap ini sesederhana menyiapkan pemroses anotasi, tetapi Anda tidak pernah tahu).

EDIT: Baru saja menemukan Hibernate JPA 2 Metamodel Generator . Tetapi masalahnya tetap ada karena saya tidak dapat menemukan tautan unduhan apa pun untuk jar.

EDIT 2: Beberapa saat telah berlalu sejak saya mengajukan pertanyaan ini, tetapi saya pikir saya akan kembali dan menambahkan tautan ke proyek Hibernate JPA Model Generator di SourceForge

Andrey
sumber

Jawaban:

87

Akan luar biasa jika seseorang juga mengetahui langkah-langkah untuk menyiapkan ini di Eclipse (Saya menganggap ini sesederhana menyiapkan pemroses anotasi, tetapi Anda tidak pernah tahu)

Ya itu. Berikut adalah implementasi dan petunjuk untuk berbagai implementasi JPA 2.0:

EclipseLink

Hibernasi

OpenJPA

DataNucleus


Implementasi Hibernate terbaru tersedia di:

Implementasi Hibernate yang lebih lama ada di:

Pascal Thivent
sumber
1
Tautan DataNucleus sudah mati.
Karl Richter
1
Tautan Hibernasi juga mati
Freelancer
43

Silakan lihat jpa-metamodels-with-maven-example .

Hibernasi

  • Kami membutuhkan org.hibernate.org:hibernate-jpamodelgen.
  • Kelas prosesor adalah org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor.

Hibernasi sebagai ketergantungan

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

Hibernasi sebagai prosesor

      <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

  • Kami membutuhkan org.apache.openjpa:openjpa.
  • Kelas prosesor adalah org.apache.openjpa.persistence.meta.AnnotationProcessor6.
  • OpenJPA sepertinya membutuhkan elemen tambahan <openjpa.metamodel>true<openjpa.metamodel>.

OpenJPA sebagai dependensi

  <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 sebagai prosesor

      <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

  • Kami membutuhkan org.eclipse.persistence:org.eclipse.persistence.jpa.modelgen.processor.
  • Kelas prosesor adalah org.eclipse.persistence.internal.jpa.modelgen.CanonicalModelProcessor.
  • EclipseLink membutuhkan persistence.xml.

EclipseLink sebagai dependensi

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

EclipseLink sebagai prosesor

    <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

  • Kami membutuhkan org.datanucleus:datanucleus-jpa-query.
  • Kelas prosesor adalah org.datanucleus.jpa.query.JPACriteriaProcessor.

DataNucleus sebagai ketergantungan

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

DataNucleus sebagai prosesor

      <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>
Jin Kwon
sumber
3
Untuk memperjelas, barang yang dihasilkan dapat digunakan dengan eclipselink, meskipun Anda menggunakan hibernate untuk membuatnya, saya tidak dapat membuat model meta dari netbeans 8 dan harus membuat proyek uji maven untuk menghasilkan barang saya
Kalpesh Soni
@ymajoros Apakah dilarang, dalam SO, untuk mengatakan something is recommendedtanpa IMHO? Saya tidak mewakili atas nama orang lain.
Jin Kwon
1
BTW, lihat jawaban Sorter untuk EclipseLink. Ini adalah konfigurasi yang telah saya gunakan selama bertahun-tahun dan berfungsi dengan sempurna. stackoverflow.com/questions/3037593/…
ymajoros
Bukankah implementasi ini spesifik, saya mencoba menggunakan metamodel yang dihasilkan Hibernate dengan EclipseLink dan mendapatkan NullPointerException
Michał Ziobro
@ymajoros Masih butuh persistence.xml, bukan?
Jin Kwon
20

Dukungan JPA 2.0 Eclipse melalui Dali (yang termasuk dalam "Eclipse IDE for JEE Developers") memiliki generator metamodel sendiri yang terintegrasi dengan Eclipse.

  1. Pilih proyek Anda di Package Explorer
  2. Pergi ke Properties -> dialog JPA
  3. Pilih folder sumber dari grup metamodel kanonik (JPA 2.0)
  4. Klik tombol Apply untuk menghasilkan kelas metamodel di folder sumber yang dipilih

masukkan deskripsi gambar di sini

Ini harus berfungsi pada penyedia JPA mana pun karena kelas yang dihasilkan adalah standar.

Lihat juga di sini .

James
sumber
Adakah cara untuk memulai prosesnya sendiri? Ini tidak dapat diandalkan menghasilkan metamodel untuk saya
ituIch
6

Untuk eclipselink, hanya ketergantungan berikut ini yang cukup untuk menghasilkan metamodel. Tidak ada lagi yang dibutuhkan.

    <dependency>
        <groupId>org.eclipse.persistence</groupId>
        <artifactId>org.eclipse.persistence.jpa.modelgen.processor</artifactId>
        <version>2.5.1</version>
        <scope>provided</scope>
    </dependency>
Tukang sortir
sumber
@Barthelomeus catatan Anda salah . EclipseLink 2.5.1+ akan menghasilkan kelas metamodel untuk entitas yang tidak terdaftar juga, cukup tentukan <exclude-unlisted-classes>false</exclude-unlisted-classes>di persisten.xml
Michele Mariotti
Perhatikan bahwa eclipselink tidak akan dihasilkan tanpapersistence.xml
Jin Kwon
5

Untuk Hibernate sebagai provider yang paling umum IMHO:

Untuk fitur build seperti Gradle, Maven, Anda harus memiliki jar Hibernate JPA 2 Metamodel Generator di classpath dan level compiler> = 1.6 hanya itu yang Anda butuhkan untuk membangun proyek dan metamodel akan dibuat secara otomatis.

Untuk IDE Eclipse 1. goto Project-> Properties-> Java Compiler-> Annotation Processing dan aktifkan. 2. Perluas Annotation Processing-> Factory Path-> Add External Jar tambahkan Hibernate JPA 2 Metamodel Generator jar, periksa jar yang baru ditambahkan dan katakan OK. Bersihkan dan Bangun selesai!

Link Hibernate JPA 2 Metamodel Generator jar link dari maven repo https://mvnrepository.com/artifact/org.hibernate/hibernate-jpamodelgen

SandeepGodara
sumber
Dalam kasus saya menambahkan <dependencies> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-jpamodelgen</artifactId> <scope>compile</scope> </dependency> </dependencies>ke pom.xml sudah cukup.
Lu55
Apakah saya memerlukan kedua konfigurasi saat menggunakan maven dan Eclipse?
Melkor
Meskipun hibernate-jpamodelgen telah ditambahkan di pom, saya harus melakukan ini dan berhasil
Freelancer
3

Karena ini adalah pertanyaan yang sangat umum, saya menulis artikel ini , yang menjadi dasar jawaban ini.

Mari kita asumsikan aplikasi kita menggunakan berikut Post, PostComment, PostDetails, dan Tagentitas, yang membentuk satu-ke-banyak, satu-ke-satu, dan banyak-ke-banyak hubungan tabel :

Metamodel Kriteria JPA

Cara membuat Metamodel Kriteria JPA

The hibernate-jpamodelgenalat yang disediakan oleh Hibernate ORM dapat digunakan untuk memindai entitas proyek dan menghasilkan Kriteria JPA Metamodel. Yang perlu Anda lakukan adalah menambahkan yang berikut ini annotationProcessorPathke maven-compiler-plugindalam pom.xmlfile konfigurasi Maven :

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

Sekarang, saat proyek dikompilasi, Anda dapat melihat bahwa di targetfolder, kelas Java berikut dibuat:

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

Metamodel entitas tag

Jika Tagentitas dipetakan sebagai berikut:

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

    @Id
    private Long id;

    private String name;

    //Getters and setters omitted for brevity
}

Kelas Tag_Metamodel dibuat seperti ini:

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

The SingularAttributedigunakan untuk dasar iddan name Tagatribut entitas JPA.

Posting entitas Metamodel

The Postentitas dipetakan seperti ini:

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

The Postentitas memiliki dua atribut dasar, iddan title, satu-ke-banyak commentskoleksi, satu-ke-satu detailsasosiasi, dan banyak-ke-banyak tagskoleksi.

Kelas Post_Metamodel dibuat sebagai berikut:

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

Atribut dasar iddan title, serta detailsasosiasi satu-ke-satu , diwakili oleh SingularAttributesementara koleksi commentsdan tagsdiwakili oleh JPA ListAttribute.

Entitas PostDetails Metamodel

The PostDetailsentitas dipetakan seperti ini:

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

Semua atribut entitas akan diwakili oleh JPA SingularAttributedi PostDetails_kelas Metamodel terkait :

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

Metamodel entitas PostComment

The PostCommentdipetakan sebagai berikut:

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

Dan, semua atribut entitas diwakili oleh JPA SingularAttributedi PostComments_kelas Metamodel terkait :

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

Menggunakan Metamodel Kriteria JPA

Tanpa Metamodel JPA, kueri API Kriteria yang perlu mengambil PostCommententitas yang difilter menurut Postjudul terkait akan terlihat seperti ini:

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();

Perhatikan bahwa kami menggunakan postliteral String saat membuat Joininstance, dan kami menggunakan titleliteral String saat mereferensikan file Post title.

Metamodel JPA memungkinkan kita untuk menghindari atribut entitas pengkodean keras, seperti yang diilustrasikan oleh contoh berikut:

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();

Menulis kueri JPA Criteria API jauh lebih mudah jika Anda menggunakan alat penyelesaian kode seperti Codota. Lihat artikel ini untuk detail lebih lanjut tentang plugin Codota IDE.

Atau, katakanlah kita ingin mengambil sebuah proyeksi DTO sementara menyaring Post titledan PostDetails createdOnatribut.

Kita dapat menggunakan Metamodel saat membuat atribut gabungan, serta saat membangun alias kolom proyeksi DTO atau saat mereferensikan atribut entitas yang perlu kita filter:

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();

Keren kan?

Vlad Mihalcea
sumber
0

Ok, berdasarkan apa yang telah saya baca di sini, saya melakukannya dengan EclipseLink dengan cara ini dan saya tidak perlu menempatkan ketergantungan prosesor pada proyek, hanya sebagai annotationProcessorPathelemen plugin compiler.

    <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
sumber