JPA / Hibernate Static Metamodel attributs non peuplé-NullPointerException
j'aimerais utiliser L'API critères JPA2 avec les objets metamodel, ce qui semble assez facile:
...
Root<JPAAlbum> albm = cq.from(JPAAlbum.class);
... albm.get(JPAAlbum_.theme) ... ;
mais cette Racine.obtenir jette toujours un NullPointerException
. JPAAlbum_.theme
a été généré automatiquement par Hibernate et ressemble à
public static volatile SingularAttribute<JPAAlbum, JPATheme> theme;
mais c'est évidemment jamais renseigné.
Suis-je raté une étape dans l'initialisation du cadre ?
EDIT: voici un extrait de comment j'utilise le JPA et le metamodel quand il est s'écraser:
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_
est une classe, alors j'ai juste import
avant) et le stacktrace associé:
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)
EDIT 2:
Dans le JBoss EntityManager guide, je peux voir que
quand L'EntityManagerFactory Hibernate est en cours de construction, il recherchera une classe de métamodèle canonique pour chacune des is gérées et dactylographiées et si elle en trouve une, elle injectera l'information de métamodèle appropriée dans ces spécifications, telles qu'elles sont décrites dans [JPA 2 Specification, section 6.2.2, page 200]
j'ai également pu vérifier avec
for (ManagedType o : em.getMetamodel().getManagedTypes()) {
log.warn("___") ;
for (Object p : o.getAttributes()) {
log.warn(((Attribute)p).getName()) ;
}
}
en veille prolongée est au courant de mon méta-modèle, les noms d'attributs sont écrits, cependant
log.warn("_+_"+JPAPhoto_.id+"_+_") ;
reste désespérément vide ...
EDIT3 ici jpaalbum entity et son méta-modèle de la classe.
Que puis-je dire d'autre sur ma configuration?..
j'utilise Hibernat 3.5.6-Finale (selon META-INF / MANIFEST.MF),
déployer sur des poissons de mer3.0.1
à partir de Netbeans 6.9.1;
et l'application repose sur EJB 3.1,
j'espère que ça va aider !
modifier 4:
malheureusement, le test de JUnit conduit à la même exception:
java.lang.NullPointerException
at org.hibernate.ejb.criteria.path.AbstractPathImpl.get(AbstractPathImpl.java:138)
at net.wazari.dao.test.TestMetaModel.foo(TestMetaModel.java:55)
un projet beaucoup plus simple est disponible ici/archive. il ne contient que mes entities et leur metamodel, plus un test de JUnit (foo crashes with metamodel, bar is okay with the usual Query.
EDIT 5:
Vous devriez être en mesure de reproduire le problème en téléchargeant la archive, construire le projet:
ant compile
or
ant dist
et démarrer le test JUnit net.wazari.dao.test.TestMetaModel
CLASSPATH=`sh runTest.sh` java org.junit.runner.JUnitCore net.wazari.dao.test.TestMetaModel
(edit runTest.sh
pour point CLASSPATH pour le droit de l'emplacement de votre JUnit4-5 jar)
toutes les dépendances d'hibernation que j'utilise doivent être incluses dans l'archive.
6 réponses
j'ai eu le même problème et il a été résolu en mettant le Model
et Model_
classe dans le même package.
j'ai eu une application Java EE 6 utilisant EclipseLink sur GlassFish avec quelques classes @StaticMetamodel créées et tout fonctionnait bien. Quand je suis passé à Hibernate 4 sur JBoss 7, j'ai commencé à avoir ces NPE aussi. J'ai commencé à enquêter et j'ai trouvé cette page:
http://docs.jboss.org/hibernate/entitymanager/3.6/reference/en/html/metamodel.html
il cite la spécification JPA 2, section 6.2.1.1 qui définit comment le métamodèle statique les classes devraient être construites. Par exemple, j'ai découvert en lisant la spécification que "l'option des différents paquets sera fournie dans une future version de cette spécification". J'ai eu les classes metamodel dans différents paquets et cela a bien fonctionné sur EclipseLink, mais c'est une fonctionnalité supplémentaire, comme le standard actuel indique ce qui suit:
- les classes de métamodèle doivent être dans le même paquet que les classes d'entités qu'elles décrivent;
- Ils doivent avoir le même nom que le les classes d'entity qu'ils décrivent, suivies d'un underscore (par exemple, Product is the entity, Product_ is the metamodel class);
- si une entité hérite d'une autre entité ou d'une superclasse cartographiée, sa classe metamodel devrait hériter de la classe metamodel qui décrit sa superclasse immédiate (par exemple si SpecialProduct étend le produit, qui étend PersistentObject, alors SpecialProduct_ devrait étendre le produit qui devrait étendre PersistentObject_).
Une Fois Que J'Ai j'ai suivi toutes les règles du spec (ce qui précède n'est qu'un résumé, veuillez vous reporter à la section 6.2.1.1 du spec pour la version complète), j'ai cessé de recevoir les exceptions.
Par le chemin, vous pouvez télécharger la spécification ici: http://jcp.org/en/jsr/detail?id=317 (cliquez sur "page de Téléchargement" pour la version finale, choisissez de télécharger le cahier des charges pour l'évaluation, l'accepter et télécharger le fichier "SR-000317 2.0" - la persistance 2_0-final-spec.PDF.)
je ne peux pas reproduire le problème. J'ai utilisé certaines de vos entités (versions simplifiées de JPAAlbum
,JPATheme
et JPATagTheme
, sans aucune interface), a généré les classes metamodel et la méthode de test rudimentaire suivante (qui s'exécute à l'intérieur d'une transaction) vient de passer:
@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, voici le code SQL généré:
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
Testé avec Hibernate EntityManager 3.5.6-Final, Hibernate JPAModelGen 1.1.0.Final, à l'extérieur de n'importe quel conteneur.
ma suggestion serait être d'abord essayer de reproduire (si reproductible) le problème dans un contexte de test de JUnit.
PS: comme note d'accompagnement, Je ne stockerais pas les classes générées dans les VCS.
mise à Jour: Voici un persistence.xml
que vous pouvez utiliser dans un cadre test:
<?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>
j'offre une solution alternative si mettre le Model et le Model_ dans le même paquet ne fonctionne pas. Vous devez ajouter une méthode init () à votre classe qui construit le SessionFactory ou EntityManager:
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
}
Ainsi, lorsque vous exécutez votre application à partir de la méthode principale ou d'un test unitaire, vous devez appeler HibernateSessionFactory.init();
dans un premier temps. Puis la NullPointerException disparaît par magie et l'application fonctionne.
c'est Ce comportement étrange semble se produire lorsque vous passez un SingularAttribute
autour via le paramètre method.
le mérite en revient à @ Canűsal qui a tout compris dans cette question: Hibernate / JPA-NullPointerException lors de l'accès au paramètre SingularAttribute