26

メタモデルオブジェクトでJPA2CriteriaAPIを使用したいのですが、これは非常に簡単なようです。

...
Root<JPAAlbum> albm = cq.from(JPAAlbum.class);
... albm.get(JPAAlbum_.theme) ... ;

ただし、このRoot.getは常に。をスローしNullPointerExceptionます。JPAAlbum_.themeHibernateによって自動的に生成され、次のようになります

public static volatile SingularAttribute<JPAAlbum, JPATheme> theme;

しかし、それは明らかに決して移入されていません。

フレームワークの初期化のステップがありませんか?

編集:これは、クラッシュしたときにJPAとメタモデルを使用する方法のスニペットです:

    CriteriaBuilder cb = em.getCriteriaBuilder();

    CriteriaQuery<JPAAlbum> cq = cb.createQuery(JPAAlbum.class) ;
    Root<JPAAlbum> albm = cq.from(JPAAlbum.class);
    cq.where(cb.equal(albm.get(JPAAlbum_.theme).get(JPATheme_.id),
                        session.getTheme().getId())) ;

JPAAlbum_はクラスなので、直前importに)および関連するスタックトレース:

Caused by: java.lang.NullPointerException
    at org.hibernate.ejb.criteria.path.AbstractPathImpl.get(AbstractPathImpl.java:138)
    at net.wazari.dao.jpa.WebAlbumsDAOBean.getRestrictionToAlbumsAllowed(WebAlbumsDAOBean.java:55)

編集2:

JBoss EntityManagerガイドでは、次のことがわかります。

Hibernate EntityManagerFactoryが構築されると、[JPA 2仕様、セクション6.2で概説されているように、既知の管理対象型ごとに正規のメタモデルクラスが検索され、見つかった場合は適切なメタモデル情報が挿入されます。 .2、200ページ]

で確認することもできます

     for (ManagedType o : em.getMetamodel().getManagedTypes()) {
            log.warn("___") ;
            for (Object p : o.getAttributes()) {
                log.warn(((Attribute)p).getName()) ;
            }
        }

Hibernateが私のメタモデルを認識していること、属性名は書かれていますが、

   log.warn("_+_"+JPAPhoto_.id+"_+_") ;

必死に空のまま...

EDIT3:これがJPAAlbumエンティティとそのメタモデルクラスです。

自分の構成について他に何がわかりますか...

  • 私はHibernat3.5.6 -Final(META-INF / MANIFEST.MFによる)を使用しています。

  • Glassfish3.0.1にデプロイする

  • Netbeans6.9.1から;

  • アプリケーションはEJB3.1に依存しています。

お役に立てば幸いです。

編集4:

残念ながら、JUnitテストでは同じ例外が発生します。

java.lang.NullPointerException
    at org.hibernate.ejb.criteria.path.AbstractPathImpl.get(AbstractPathImpl.java:138)
    at net.wazari.dao.test.TestMetaModel.foo(TestMetaModel.java:55)

はるかに単純なプロジェクトがここ/ tarballで利用可能です。エンティティとそのメタモデル、およびJUnitテストのみが含まれています(fooはメタモデルでクラッシュし、barは通常のクエリで問題ありません。

編集5:

tarballをダウンロードし、プロジェクトをビルドすることで、問題を再現できるはずです。

ant compile
or
ant dist

JUnitテストを開始しますnet.wazari.dao.test.TestMetaModel

 CLASSPATH=`sh runTest.sh` java org.junit.runner.JUnitCore  net.wazari.dao.test.TestMetaModel

runTest.shCLASSPATHがJUnit4-5 jarの正しい場所を指すように編集します)

私が使用するすべての休止状態の依存関係は、アーカイブに含まれている必要があります。

4

9 に答える 9

53

Model同じ問題が発生しましたが、とModel_クラスを同じパッケージに入れることで修正されました。

于 2011-02-03T21:43:56.853 に答える
12

GlassFishでEclipseLinkを使用するJavaEE6アプリケーションがあり、いくつかの@StaticMetamodelクラスが作成され、すべてが正常に機能していました。JBoss7でHibernate4に切り替えたとき、これらのNPEも取得し始めました。調査を開始し、次のページを見つけました。

http://docs.jboss.org/hibernate/entitymanager/3.6/reference/en/html/metamodel.html

静的メタモデルクラスの構築方法を定義するJPA2仕様のセクション6.2.1.1を引用しています。たとえば、仕様を読んで、「この仕様の将来のリリースで、さまざまなパッケージのオプションが提供される」ことがわかりました。さまざまなパッケージにメタモデルクラスがあり、EclipseLinkで正常に機能しましたが、現在の標準では次のように示されているため、これは追加機能です。

  • メタモデルクラスは、それらが記述するエンティティクラスと同じパッケージに含まれている必要があります。
  • それらは、説明するエンティティクラスと同じ名前で、その後にアンダースコアを付ける必要があります(たとえば、Productはエンティティ、Product_はメタモデルクラス)。
  • エンティティが別のエンティティまたはマップされたスーパークラスから継承する場合、そのメタモデルクラスは、その直接のスーパークラスを記述するメタモデルクラスから継承する必要があります(たとえば、SpecialProductがPersistentObjectを拡張するProductを拡張する場合、SpecialProduct_はPersistentObject_を拡張するProduct_を拡張する必要があります)。

仕様のすべてのルール(上記は単なる要約です。完全なバージョンについては仕様のセクション6.2.1.1を参照してください)に従うと、例外の取得を停止しました。

ちなみに、ここから仕様をダウンロードできます:http: //jcp.org/en/jsr/detail ?id=317 (最終リリースの「ダウンロードページ」をクリックし、評価のために仕様をダウンロードすることを選択し、同意し、ファイル「SR-0003172.0仕様」-persistence-2_0-final-spec.pdfをダウンロードします。

于 2011-11-10T14:32:43.653 に答える
8

問題を再現できません。いくつかのエンティティ(の簡略化されたバージョンJPAAlbumJPAThemeおよびJPATagTheme、インターフェイスなし)を使用して、メタモデルクラスを生成し、次の基本的なテストメソッド(トランザクション内で実行)が合格しました。

@Test
public void foo() {
    CriteriaBuilder builder = em.getCriteriaBuilder();
    CriteriaQuery<JPAAlbum> query = builder.createQuery(JPAAlbum.class);

    Root<JPAAlbum> album = query.from(JPAAlbum.class);

    Assert.assertNotNull(album.get(JPAAlbum_.theme)); // no problem here

    query.where(builder.equal(album.get(JPAAlbum_.theme).get(JPATheme_.id), 1L));

    List<JPAAlbum> results = em.createQuery(query).getResultList();
}

FWIW、生成されたSQLは次のとおりです。

select
    jpaalbum0_.ID as ID32_,
    jpaalbum0_.AlbumDate as AlbumDate32_,
    jpaalbum0_.Description as Descript3_32_,
    jpaalbum0_.Nom as Nom32_,
    jpaalbum0_.Picture as Picture32_,
    jpaalbum0_.Theme as Theme32_ 
from
    Album jpaalbum0_ 
where
    jpaalbum0_.Theme=1

Hibernate EntityManager 3.5.6-Final、Hibernate JPAModelGen 1.1.0.Final、任意のコンテナーの外部でテスト済み。

私の提案は、最初にJUnitテストコンテキストで問題を再現しようとすることです(再現可能な場合)。

PS:ちなみに、生成されたクラスはVCSに保存しません。


更新:persistence.xmlテストコンテキストで使用できるものは次のとおりです。

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
  version="2.0">
  <persistence-unit name="MyPu" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>

    <class>com.stackoverflow.q3854687.JPAAlbum</class>
    <class>com.stackoverflow.q3854687.JPATheme</class>
    <class>com.stackoverflow.q3854687.JPATagTheme</class>

    <exclude-unlisted-classes>true</exclude-unlisted-classes>

    <properties>
      <!-- Common properties -->
      <property name="javax.persistence.jdbc.driver" value="${jdbc.driver}" />
      <property name="javax.persistence.jdbc.url" value="${jdbc.url}" />
      <property name="javax.persistence.jdbc.user" value="${jdbc.user}" />
      <property name="javax.persistence.jdbc.password" value="${jdbc.password}" />

      <!-- Hibernate specific properties -->
      <property name="hibernate.dialect" value="${jdbc.dialect}" />
      <!--
      <property name="hibernate.show_sql" value="true"/>
      -->
      <property name="hibernate.format_sql" value="true" />
      <property name="hibernate.hbm2ddl.auto" value="update" />   
    </properties>
  </persistence-unit>
</persistence>
于 2010-11-07T15:06:01.573 に答える
1

ModelとModel_を同じパッケージに入れても機能しない場合は、別の解決策を提供します。SessionFactoryまたはEntityManagerを構築するクラスに1つのinit()メソッドを追加する必要があります。

public class HibernateSessionFactory {
  private static SessionFactory factory;

  static {
    try {
        factory = new Configuration().configure().buildSessionFactory();
    } catch (Throwable ex) {
        throw new ExceptionInInitializerError(ex);
    }
  }

  public static SessionFactory getFactory() {
    return factory;
  }

  public static void init(){} //does nothing but elimating the NULLPOINTEREXCEPTION
}

したがって、メインメソッドまたは単体テストからアプリケーションを実行する場合は、HibernateSessionFactory.init();最初に呼び出す必要があります。その後、NullPointerExceptionが魔法のように消え、アプリケーションが動作します。

SingularAttributeこの奇妙な振る舞いは、メソッドパラメータを介してアラウンドを渡すときに発生するようです。

クレジットは、この質問ですべてを理解した@CanÜNSALに送られます:Hibernate/JPA-SingularAttributeパラメーターにアクセスするときのNullPointerException

于 2017-01-11T14:07:27.840 に答える
1

2019-04-24

未入力のメタモデルクラス属性の通常の問題は、メタモデルクラスが対応する管理対象クラスとは異なるパッケージにある場合です。

最新のJPA2.2仕様では、対応するマネージクラスと同じパッケージにメタモデルクラスを含める必要があります。

参照:ページ238、§6.2.1.1正規メタモデル

于 2019-04-24T11:55:55.950 に答える
0

参考までに、Hibernateがメタモデル属性を作成しても初期化せず、NullPointerException使用しようとすると'sが発生する場合がありました。

public class Upper {
    public String getLabel() { return this.label; }
    public void setLabel(String label) { this.label = label; }
}

public class Lower extends Upper {
   @Override
   public String getLabel() { return super.getLabel(); }
}

Hibernateは、両方のクラスlabelで属性宣言を生成します。

@Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
@StaticMetamodel(Upper.class)
public abstract class Upper_ {
    public static volatile SingularAttribute<Upper, String> label;
}

@Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
@StaticMetamodel(Lower.class)
public abstract class Lower_ {
    public static volatile SingularAttribute<Lower, String> label;
}

...初期化されますが、nullのUpper_.labelままになります。Lower_.label

ブーム

于 2018-08-07T22:11:32.097 に答える
0

クラスとメタモデルは同じパッケージに含まれている必要があります。

フォルダエンティティ:

  • エジェ
  • Eje_
  • エレメント
  • エレメント_

メタモデルコードの一例を添付しました

import javax.annotation.Generated;
import javax.persistence.metamodel.SetAttribute;
import javax.persistence.metamodel.SingularAttribute;
import javax.persistence.metamodel.StaticMetamodel;
import java.util.Date;

@Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
@StaticMetamodel(Eje.class)
public abstract class Eje_ {
    public static volatile SingularAttribute<Eje, Integer> id;
    public static volatile SingularAttribute<Eje, String> name;
    public static volatile SingularAttribute<Eje, Integer> users;
    public static volatile SingularAttribute<Eje, Date> createdAt;
    public static volatile SingularAttribute<Eje, Date> updatedAt;
    public static volatile SetAttribute<Eje, FactorCritico> factorCriticos;
}
于 2018-08-17T20:03:22.957 に答える
0

上記のいずれもこのNPEの問題を解決しない場合は、Setではなくエンティティ関係でListを使用しているかどうかを確認することもできます。

Listを使用すると、メタモデルでSetAttributeの代わりにListAttributeを宣言する必要があることがわかりました。そうしないと、NullPointerExceptionが発生し、スタックトレース全体が表示されない場合、メタモデルがJPA仕様によって初期化されていないことに気付かないでしょう。 。

于 2018-11-09T16:01:16.433 に答える
0

デビーの答えは私をそこへの道の半分に導いた。

別の「名前の一致」ブードゥーの落とし穴があります。

短縮版:

「名前」は、「プロパティ」のモデルとメタモデルの間で一致する必要があります。

長いバージョン:

簡単ではない名前を使用していました。

最初にエンティティ:

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import java.io.Serializable;
import java.time.OffsetDateTime;
import java.util.LinkedHashSet;
import java.util.Set;

@Entity
@Table(name = "DepartmentTable")
public class DepartmentJpaEntity implements Serializable {

    @Id
    @Column(name = "DepartmentKey", unique = true)
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long departmentKey;
    @Column(name = "DepartmentName", unique = true)
    private String departmentName;
    @Column(name = "CreateOffsetDateTime", columnDefinition = "TIMESTAMP WITH TIME ZONE")
    private OffsetDateTime createOffsetDateTime;
    @OneToMany(
            mappedBy = "parentDepartmentJpaEntity",
            cascade = CascadeType.PERSIST,
            orphanRemoval = true,
            fetch = FetchType.LAZY /* Lazy or Eager here */
    )

    private Set<EmployeeJpaEntity> employeeJpaEntities = new LinkedHashSet<>();

}

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import java.io.Serializable;
import java.time.OffsetDateTime;

@Entity
@Table(name = "EmployeeTable")
public class EmployeeJpaEntity implements Serializable {

    @Id
    @Column(name = "EmployeeKey", unique = true)
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long employeeKey;

    @Column(name = "Ssn")
    private String ssn;

    @Column(name = "LastName")
    private String lastName;

    @Column(name = "FirstName")
    private String firstName;

    @Column(name = "CreateOffsetDateTime", columnDefinition = "TIMESTAMP WITH TIME ZONE")
    private OffsetDateTime createOffsetDateTime;

    //region Navigation
    
    @ManyToOne(fetch = FetchType.LAZY, targetEntity = DepartmentJpaEntity.class, cascade = CascadeType.PERSIST )
    @JoinColumn(name = "DepartmentForeignKey")
        private DepartmentJpaEntity parentDepartmentJpaEntity;
    //endregion

}

私のややデフォルトではない名前に注意してください。OnetoManyおよびManyToOneオブジェクト名に注意してください。

さて、私のメタモデル:

import javax.persistence.metamodel.SetAttribute;
import javax.persistence.metamodel.SingularAttribute;

@javax.persistence.metamodel.StaticMetamodel(DepartmentJpaEntity.class)

public class DepartmentJpaEntity_ {
  public static volatile SingularAttribute<DepartmentJpaEntity, Long> departmentKey;
  public static volatile SetAttribute<DepartmentJpaEntity, EmployeeJpaEntity> employees; /* DOES NOT WORK :(  */
}

しかし、私は同じ名前の魔法のブードゥー教徒なので、これ(以下)は機能します:

import javax.persistence.metamodel.SetAttribute;
import javax.persistence.metamodel.SingularAttribute;

@javax.persistence.metamodel.StaticMetamodel(DepartmentJpaEntity.class)

public class DepartmentJpaEntity_ {
  public static volatile SingularAttribute<DepartmentJpaEntity, Long> departmentKey;
  public static volatile SetAttribute<DepartmentJpaEntity, EmployeeJpaEntity> employeeJpaEntities;
}

そしてもう1つ:

import javax.persistence.metamodel.SingularAttribute;

@javax.persistence.metamodel.StaticMetamodel(EmployeeJpaEntity.class)

public class EmployeeJpaEntity_ {
  public static volatile SingularAttribute<EmployeeJpaEntity, Long> employeeKey;
  public static volatile SingularAttribute<EmployeeJpaEntity, DepartmentJpaEntity> parentDepartment;  /*does NOT work...its null at run time...no voodoo name matching */
}

しかし、これは機能します:

import javax.persistence.metamodel.SingularAttribute;

@javax.persistence.metamodel.StaticMetamodel(EmployeeJpaEntity.class)

public class EmployeeJpaEntity_ {
  public static volatile SingularAttribute<EmployeeJpaEntity, Long> employeeKey;
  public static volatile SingularAttribute<EmployeeJpaEntity, DepartmentJpaEntity> parentDepartmentJpaEntity;
}

私が意図的に非「標準」の名前を使用する理由の1つは、最初にこれらのブードゥー設定の問題を洗い流すためです......早期に失敗するために... vs failLater(できればQAではなく誰かがその時点で良性と思われるプロパティの名前を変更したため、本番環境で)問題が発生しました。

于 2020-06-11T15:41:08.747 に答える