Come generare l'entità JPA Metamodel?


94

Nello spirito della sicurezza dei tipi associata a CriteriaQuery, JPA 2.0 ha anche un'API per supportare la rappresentazione Metamodel delle entità.

Qualcuno è a conoscenza di un'implementazione completamente funzionale di questa API (per generare il Metamodel anziché creare manualmente le classi di metamodel)? Sarebbe fantastico se qualcuno conoscesse anche i passaggi per configurarlo in Eclipse (presumo sia semplice come configurare un processore di annotazioni, ma non si sa mai).

EDIT: sono appena incappato in Hibernate JPA 2 Metamodel Generator . Ma il problema rimane poiché non riesco a trovare alcun link per il download per il vaso.

EDIT 2: È passato del tempo da quando ho posto questa domanda, ma ho pensato di tornare e aggiungere un collegamento al progetto Hibernate JPA Model Generator su SourceForge

Risposte:


87

Sarebbe fantastico se qualcuno conoscesse anche i passaggi per configurarlo in Eclipse (presumo sia semplice come configurare un processore di annotazioni, ma non si sa mai)

Sì. Ecco le implementazioni e le istruzioni per le varie implementazioni JPA 2.0:

EclipseLink

Ibernazione

OpenJPA

DataNucleus


L'ultima implementazione di Hibernate è disponibile su:

Una vecchia implementazione di Hibernate si trova a:


1
Il collegamento DataNucleus è morto.
Karl Richter

1
Anche il collegamento Hibernate è morto
Freelancer

43

Dai un'occhiata a jpa-metamodels-with-maven-example .

Ibernazione

  • Abbiamo bisogno org.hibernate.org:hibernate-jpamodelgen.
  • La classe del processore è org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor.

Iberna come dipendenza

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

Iberna come processore

      <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

  • Abbiamo bisogno org.apache.openjpa:openjpa.
  • La classe del processore è org.apache.openjpa.persistence.meta.AnnotationProcessor6.
  • OpenJPA sembra richiedere un elemento aggiuntivo <openjpa.metamodel>true<openjpa.metamodel>.

OpenJPA come dipendenza

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

      <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

  • Abbiamo bisogno org.eclipse.persistence:org.eclipse.persistence.jpa.modelgen.processor.
  • La classe del processore è org.eclipse.persistence.internal.jpa.modelgen.CanonicalModelProcessor.
  • EclipseLink richiede persistence.xml.

EclipseLink come dipendenza

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

EclipseLink come processore

    <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

  • Abbiamo bisogno org.datanucleus:datanucleus-jpa-query.
  • La classe del processore è org.datanucleus.jpa.query.JPACriteriaProcessor.

DataNucleus come dipendenza

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

DataNucleus come processore

      <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
Giusto per essere chiari, il materiale generato può essere utilizzato con eclipselink, anche se usi l'ibernazione per generarlo, non ho potuto generare meta modello da netbeans 8 e ho dovuto creare un progetto di prova esperto per generare le mie cose
Kalpesh Soni

@ymajoros È vietato, in SO, dire something is recommendedsenza IMHO? Non rappresento per conto di nessun altro.
Jin Kwon

1
BTW, vedi la risposta di Sorter per EclipseLink. Questa è la configurazione che utilizzo da anni e funziona perfettamente. stackoverflow.com/questions/3037593/...
ymajoros

Questa implementazione non è specifica, cerco di utilizzare il metamodello generato da Hibernate con EclipseLink e ottenere NullPointerException
Michał Ziobro

@ymajoros ha ancora bisogno di un persistence.xml, non è vero?
Jin Kwon

20

Il supporto JPA 2.0 di Eclipse tramite Dali (incluso in "Eclipse IDE for JEE Developers") ha il proprio generatore di metamodelli integrato con Eclipse.

  1. Seleziona il tuo progetto in Package Explorer
  2. Vai a Proprietà -> JPA finestra di dialogo
  3. Seleziona la cartella di origine da Canonical metamodel (JPA 2.0) gruppo
  4. Fare clic sul pulsante Applica per generare classi di metamodello nella cartella di origine selezionata

inserisci qui la descrizione dell'immagine

Questo dovrebbe funzionare su qualsiasi provider JPA poiché le classi generate sono standard.

Vedi anche qui .


C'è un modo per dare il via al processo da soli? Questo non produce in modo affidabile il metamodello per me
questo è

6

Per eclipselink, solo la seguente dipendenza è sufficiente per generare il metamodello. Non serve altro.

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


@Barthelomeus la tua nota è falsa . EclipseLink 2.5.1+ genererà classi di metamodelli anche per entità non <exclude-unlisted-classes>false</exclude-unlisted-classes>elencate , basta specificare in persisetence.xml
Michele Mariotti

Nota che eclipselink non verrà generato senzapersistence.xml
Jin Kwon

5

Per Hibernate come provider che è IMHO più comune:

In caso di strumenti di compilazione come Gradle, Maven è necessario avere il jar Hibernate JPA 2 Metamodel Generator nel percorso di classe e nel livello del compilatore> = 1.6 che è tutto ciò di cui hai bisogno per compilare il progetto e il metamodello verrà generato automaticamente.

In caso di IDE Eclipse 1. vai a Project-> Properties-> Java Compiler-> Annotation Processing e abilitalo. 2. Espandere Elaborazione annotazioni-> Percorso di fabbrica-> Aggiungi jar esterno aggiungere il jar di Hibernate JPA 2 Metamodel Generator, controllare il jar appena aggiunto e dire OK. Pulisci e costruisci fatto!

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


Nel mio caso è <dependencies> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-jpamodelgen</artifactId> <scope>compile</scope> </dependency> </dependencies>stato sufficiente aggiungere a pom.xml.
Lu55

Ho bisogno di entrambe le configurazioni quando utilizzo Maven ed Eclipse?
Melkor

anche se hibernate-jpamodelgen è stato aggiunto nel pom, ho dovuto farlo e ha funzionato
Freelancer

3

Poiché questa è una domanda molto comune, ho scritto questo articolo , su cui si basa questa risposta.

Supponiamo che la nostra applicazione utilizza la seguente Post, PostComment, PostDetails, e Taggli enti, che formano un uno-a-molti, uno-a-uno, e molti-a-molti rapporti della tabella :

Metamodello dei criteri JPA

Come generare il metamodello dei criteri JPA

Lo hibernate-jpamodelgenstrumento fornito da Hibernate ORM può essere utilizzato per scansionare le entità del progetto e generare il metamodello dei criteri JPA. Tutto quello che devi fare è aggiungere quanto segue annotationProcessorPathal file di configurazione di maven-compiler-pluginMaven 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>

Ora, quando il progetto è compilato, puoi vedere che nella targetcartella vengono generate le seguenti classi Java:

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

Tag entità Metamodel

Se l' Tagentità è mappata come segue:

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

    @Id
    private Long id;

    private String name;

    //Getters and setters omitted for brevity
}

La Tag_classe Metamodel viene generata in questo modo:

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

Il SingularAttributeè utilizzato per la base idename Tag attributi JPA entità.

Post entity Metamodel

L' Postentità è mappata in questo modo:

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

L' Postentità ha due attributi di base ide title, una commentsraccolta uno-a-molti , un'associazione uno-a-uno detailse un molti-a-moltitags raccolta .

La Post_classe Metamodel viene generata come segue:

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

Gli attributi di base ide title, così come l' detailsassociazione uno-a-uno , sono rappresentati da un SingularAttributementre le commentse le tagscollezioni sono rappresentate dall'APPListAttribute .

Entità PostDetails Metamodel

L' PostDetailsentità è mappata in questo modo:

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

Tutti gli attributi dell'entità saranno rappresentati dall'APP SingularAttributenella PostDetails_classe Metamodel associata :

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

Entità PostComment Metamodel

Il PostCommentè mappato come segue:

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

Inoltre, tutti gli attributi dell'entità sono rappresentati dall'APP SingularAttributenella PostComments_classe Metamodel associata :

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

Utilizzo del metamodello dei criteri JPA

Senza il metamodello JPA, una query API Criteria che deve recuperare le PostCommententità filtrate in base al Posttitolo associato sarebbe simile a questa:

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

Si noti che abbiamo utilizzato il valore postletterale String durante la creazione Joindell'istanza e il valore titleletterale String quando si fa riferimento aPost title .

Il metamodello JPA ci consente di evitare attributi di entità hardcoded, come illustrato dal seguente esempio:

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

Scrivere le query API dei criteri JPA è molto più semplice se si utilizza uno strumento di completamento del codice come Codota. Dai un'occhiata a questo articolo per maggiori dettagli sul plug-in IDE Codota.

Oppure, supponiamo di voler recuperare una proiezione DTO filtrando il Post titlee ilPostDetails createdOn attributi e.

Possiamo usare il Metamodel quando creiamo gli attributi di join, così come quando creiamo gli alias della colonna di proiezione DTO o quando facciamo riferimento agli attributi dell'entità che dobbiamo filtrare:

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

Fantastico, vero?


0

Ok, in base a quanto ho letto qui, l'ho fatto con EclipseLink in questo modo e non avevo bisogno di mettere la dipendenza del processore al progetto, solo come annotationProcessorPathelemento del plugin del compilatore.

    <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>
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.