メタモデルオブジェクトで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.sh
CLASSPATHがJUnit4-5jarの正しい場所を指すようにします)
私が使用するすべてのHibernate依存関係は、アーカイブに含まれている必要があります。
同じ問題が発生しましたが、Model
クラスとModel_
クラスを同じパッケージに入れることで修正されました。
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で正常に機能しましたが、現在の標準では次のように示されているため、これは追加機能です。
仕様のすべてのルールに従った後(上記は要約にすぎません。完全なバージョンについては、仕様のセクション6.2.1.1を参照してください)、例外の取得を停止しました。
ちなみに、ここから仕様をダウンロードできます: http://jcp.org/en/jsr/detail?id=317 (最終リリースの「ダウンロードページ」をクリックして、ダウンロードすることを選択してください評価用の仕様書に同意し、ファイル「SR-000317 2.0仕様書」(persistence-2_0-final-spec.pdf)をダウンロードします。
問題を再現できません。いくつかのエンティティ(JPAAlbum
、JPATheme
、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>
参考までに、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のままにします。
ブーム。
上記のいずれでもこのNPEの問題が解決しない場合は、エンティティの関係でSetではなくListを使用しているかどうかを確認することもできます。
Listを使用すると、メタモデルでSetAttributeの代わりにListAttributeを宣言する必要があることがわかりました。そうしないと、NullPointerExceptionが発生し、スタックトレース全体が表示されない場合、メタモデルがJPA仕様によって初期化されていないことに気付かないでしょう。 。
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
クラスとメタモデルは同じパッケージに含まれている必要があります。
フォルダエンティティ:
メタモデルコードの一例を添付しました
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;
}
2019-04-24
未入力のメタモデルクラス属性の通常の問題は、メタモデルクラスが対応するマネージクラスとは異なるパッケージにある場合です。
最新のJPA 2.2仕様では、対応するマネージクラスと同じパッケージにメタモデルクラスを含める必要があります。
参照 :238ページ、§6.2.1.1正規メタモデル