web-dev-qa-db-ja.com

JPA / Hibernate静的メタモデル属性が入力されていない-NullPointerException

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

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

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

public static volatile SingularAttribute<JPAAlbum, JPATheme> theme;

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

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

EDIT:これはクラッシュ時に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:

JBossEntityManagerガイドでそれを見ることができます

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による)を使用します。

  • glassfishにデプロイする3.0.1

  • netbeansから6.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-5jarの正しい場所を指すようにします)

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

22
Kevin

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

46
debbie

GlassFishでEclipseLinkを使用するJava EE 6アプリケーションがいくつかの@StaticMetamodelクラスを作成し、すべてが正常に機能していました。JBoss7でHibernate 4に切り替えると、これらの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-000317 2.0仕様書」(persistence-2_0-final-spec.pdf)をダウンロードします。

11

問題を再現できません。いくつかのエンティティ(JPAAlbumJPAThemeJPATagThemeの簡略版、インターフェイスなし)を使用して、メタモデルクラスと次の基本的なテストメソッドを生成しました(内部で実行)トランザクション)は通過します:

@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>
8
Pascal Thivent

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

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

...そしてUpper_.labelを初期化しますが、Lower_.labelはnullのままにします。

ブーム

0
Archie

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

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

0
Eduardo

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

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

この奇妙な動作は、メソッドパラメータを介してSingularAttributeを渡すと発生するようです。

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

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;
}
0

2019-04-24

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

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

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

0
Z3d4s