Como gerar o Metamodelo da entidade JPA?

94

No espírito de segurança de tipo associado ao CriteriaQuery JPA 2.0 também tem uma API para suportar a representação de entidades de Metamodelo .

Alguém está ciente de uma implementação totalmente funcional desta API (para gerar o Metamodelo em vez de criar as classes do metamodelo manualmente)? Seria incrível se alguém também conhecesse as etapas para configurar isso no Eclipse (presumo que seja tão simples quanto configurar um processador de anotação, mas você nunca sabe).

EDIT: Acabei de descobrir o Gerador de Metamodelo Hibernate JPA 2 . Mas o problema permanece, já que não consigo encontrar nenhum link de download para o jar.

EDIT 2: Já se passou um tempo desde que fiz esta pergunta, mas pensei em voltar e adicionar um link para o projeto Hibernate JPA Model Generator no SourceForge

Andrey
fonte

Respostas:

87

Seria incrível se alguém também conhecesse as etapas para configurar isso no Eclipse (presumo que seja tão simples quanto configurar um processador de anotação, mas nunca se sabe)

Sim, ele é. Aqui estão as implementações e instruções para as várias implementações JPA 2.0:

EclipseLink

Hibernar

OpenJPA

DataNucleus


A implementação mais recente do Hibernate está disponível em:

Uma implementação mais antiga do Hibernate está em:

Pascal Thivent
fonte
1
O link DataNucleus está morto.
Karl Richter
1
O link do Hibernate também está morto
Freelancer,
43

Por favor, dê uma olhada em jpa-metamodels-with-maven-example .

Hibernar

  • Nós precisamos org.hibernate.org:hibernate-jpamodelgen.
  • A classe do processador é org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor.

Hibernar como uma dependência

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

Hibernate como um processador

      <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

  • Nós precisamos org.apache.openjpa:openjpa.
  • A classe do processador é org.apache.openjpa.persistence.meta.AnnotationProcessor6.
  • OpenJPA parece requerer elemento adicional <openjpa.metamodel>true<openjpa.metamodel>.

OpenJPA como uma dependência

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

      <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

  • Nós precisamos org.eclipse.persistence:org.eclipse.persistence.jpa.modelgen.processor.
  • A classe do processador é org.eclipse.persistence.internal.jpa.modelgen.CanonicalModelProcessor.
  • EclipseLink requer persistence.xml.

EclipseLink como uma dependência

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

EclipseLink como processador

    <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

  • Nós precisamos org.datanucleus:datanucleus-jpa-query.
  • A classe do processador é org.datanucleus.jpa.query.JPACriteriaProcessor.

DataNucleus como uma dependência

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

DataNucleus como processador

      <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
fonte
3
Só para ficar claro, o material gerado pode ser usado com eclipselink, mesmo que você use o hibernate para gerá-lo, eu não consegui gerar um metamodelo do netbeans 8 e tive que criar um projeto de teste maven para gerar meu material
Kalpesh Soni
@ymajoros É proibido, no SO, dizer something is recommendedsem IMHO? Não estou representando em nome de ninguém.
Jin Kwon
1
BTW, consulte a resposta do Classificador para EclipseLink. Esta é a configuração que uso há anos e funciona perfeitamente. stackoverflow.com/questions/3037593/…
ymajoros
Não é esta implementação específica, eu tento usar o metamodelo gerado pelo Hibernate com EclipseLink e obter NullPointerException
Michał Ziobro
@ymajoros Ainda precisa de um persistence.xml, não é?
Jin Kwon
20

O suporte JPA 2.0 do Eclipse através do Dali (que está incluído no "Eclipse IDE para JEE Developers") tem seu próprio gerador de metamodelo integrado ao Eclipse.

  1. Selecione seu projeto no Package Explorer
  2. Vá para Propriedades -> caixa de diálogo JPA
  3. Selecionar pasta de origem da Canonical metamodelo (JPA 2.0) grupo
  4. Clique no botão Aplicar para gerar classes de metamodelo na pasta de origem selecionada

insira a descrição da imagem aqui

Isso deve funcionar em qualquer provedor JPA, pois as classes geradas são padrão.

Veja também aqui .

James
fonte
Existe alguma maneira de iniciar o processo sozinho? Isso não produz o metamodelo de maneira confiável para mim
isso é
6

Para eclipselink, apenas a seguinte dependência é suficiente para gerar o metamodelo. Nada mais é necessário.

    <dependency>
        <groupId>org.eclipse.persistence</groupId>
        <artifactId>org.eclipse.persistence.jpa.modelgen.processor</artifactId>
        <version>2.5.1</version>
        <scope>provided</scope>
    </dependency>
Classificador
fonte
@Barthelomeus sua nota é falsa . EclipseLink 2.5.1+ gerará classes de metamodelo para entidades não <exclude-unlisted-classes>false</exclude-unlisted-classes>listadas também, basta especificar em persisetence.xml
Michele Mariotti
Observe que o eclipselink não será gerado sempersistence.xml
Jin Kwon
5

Para o Hibernate como provedor, qual é o IMHO mais comum:

No caso de ferramentas de construção como Gradle, Maven, você precisa ter o jar do Gerador de Metamodelo Hibernate JPA 2 no classpath e nível do compilador> = 1.6 que é tudo que você precisa para construir o projeto e o metamodelo será gerado automaticamente.

No caso do IDE Eclipse 1. vá para Projeto-> Propriedades-> Compilador Java-> Processamento de anotação e ative-o. 2. Expanda Processamento de anotação-> Caminho de fábrica-> Adicionar jar externo adicione jar do gerador de metamodelo JPA 2 do Hibernate, verifique o jar recém-adicionado e diga OK. Limpar e construir pronto!

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

SandeepGodara
fonte
No meu caso, adicionar <dependencies> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-jpamodelgen</artifactId> <scope>compile</scope> </dependency> </dependencies>ao pom.xml foi o suficiente.
Lu55
Preciso das duas configurações ao usar o maven e o Eclipse?
Melkor
embora o hibernate-jpamodelgen tenha sido adicionado ao pom, eu tive que fazer isso e funcionou
Freelancer
3

Como esta é uma pergunta muito comum, escrevi este artigo , no qual esta resposta se baseia.

Vamos supor que o nosso aplicativo usa o seguinte Post, PostComment, PostDetails, e Tagentidades, que formam um um-para-muitos, um-para-um, e muitos-para-muitos relações de tabela :

Metamodelo de critérios JPA

Como gerar o Metamodelo de Critérios JPA

A hibernate-jpamodelgenferramenta fornecida pelo Hibernate ORM pode ser usada para escanear as entidades do projeto e gerar o Metamodelo de Critérios JPA. Tudo que você precisa fazer é adicionar o seguinte annotationProcessorPathao arquivo de configuração maven-compiler-plugindo 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>

Agora, quando o projeto é compilado, você pode ver que na targetpasta, as seguintes classes Java são geradas:

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

Metamodelo de entidade de tag

Se a Tagentidade for mapeada da seguinte maneira:

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

    @Id
    private Long id;

    private String name;

    //Getters and setters omitted for brevity
}

A Tag_classe Metamodel é gerada assim:

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

O SingularAttributeé usado para os atributos básicos ide de name Tagentidade JPA.

Metamodelo de entidade post

A Postentidade é mapeada assim:

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

A Postentidade tem dois atributos básicos ide title, uma commentscoleção de um para muitos , uma detailsassociação de um para um e uma tagscoleção de muitos para muitos .

A Post_classe Metamodel é gerada da seguinte maneira:

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

Os atributos básicos ide title, bem como a detailsassociação um para um , são representados por um SingularAttributeenquanto as coleções commentse tagssão representadas pelo JPA ListAttribute.

Metamodelo de entidade PostDetails

A PostDetailsentidade é mapeada assim:

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

Todos os atributos da entidade serão representados pelo JPA SingularAttributena PostDetails_classe Metamodelo associada :

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

Metamodelo de entidade PostComment

O PostCommenté mapeado da seguinte forma:

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

E todos os atributos de entidade são representados pelo JPA SingularAttributena PostComments_classe Metamodelo associada :

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

Usando o Metamodelo de Critérios JPA

Sem o Metamodelo JPA, uma consulta de Criteria API que precisa buscar as PostCommententidades filtradas por seus Posttítulos associados ficaria assim:

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

Observe que usamos o postliteral String ao criar a Joininstância e o titleliteral String ao fazer referência ao Post title.

O Metamodelo JPA nos permite evitar atributos de entidade de codificação permanente, conforme ilustrado pelo seguinte exemplo:

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

Escrever consultas de API de critérios JPA é muito mais fácil se você estiver usando uma ferramenta de auto-completar de código como Codota. Confira este artigo para obter mais detalhes sobre o plugin Codota IDE.

Ou digamos que queremos buscar uma projeção DTO enquanto filtramos Post titleos PostDetails createdOnatributos e.

Podemos usar o Metamodelo ao criar os atributos de junção, bem como ao construir os aliases da coluna de projeção DTO ou ao fazer referência aos atributos de entidade que precisamos filtrar:

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

Legal certo?

Vlad Mihalcea
fonte
0

Ok, com base no que li aqui, fiz isso com EclipseLink desta forma e não precisei colocar a dependência do processador no projeto, apenas como um annotationProcessorPathelemento do plugin do compilador.

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