Attributi Metadodel statici JPA / Hibernate non popolati – NullPointerException

Vorrei utilizzare l’API dei criteri JPA2 con gli oggetti metamodel, che sembra essere piuttosto semplice:

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

ma questo Root.get genera sempre una NullPointerException . JPAAlbum_.theme stato generato automaticamente da Hibernate e sembra

 public static volatile SingularAttribute theme; 

ma ovviamente non è mai popolato.

Mi manca un passo nell’inizializzazione del framework?

EDIT: ecco un frammento di come uso JPA e il metamodel quando si blocca:

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

( JPAAlbum_ è una class, quindi ho appena import prima) e lo stacktrace associato:

 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) 

MODIFICA 2:

Nella guida di JBoss EntityManager, posso vederlo

Quando Hibernate EntityManagerFactory è in fase di costruzione, cercherà una class metamodellica canonica per ognuno dei tipi gestiti gestiti, e se trova dei dati verrà iniettata loro le informazioni metamodell appropriate, come indicato in [Specifica JPA 2, sezione 6.2 .2, pg 200]

Potrei anche verificare con

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

che Hibernate è a conoscenza del mio metamodello, tuttavia i nomi degli attributi sono scritti

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

rimane disperatamente vuoto …

EDIT3 : ecco l’ quadro JPAAlbum e la sua class metamodel .

Cos’altro posso dire sulla mia configurazione …

  • Uso Hibernat 3.5.6-Final (secondo META-INF / MANIFEST.MF),

  • distribuire su Glassfish 3.0.1

  • da Netbeans 6.9.1 ;

  • e l’applicazione si basa su EJB 3.1 ,

Spero che questo possa aiutare !

MODIFICA 4:

sfortunatamente, il test JUnit porta alla stessa eccezione:

 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 progetto molto più semplice è disponibile qui / tarball . Contiene solo le mie quadro e il loro metamodello, oltre a un test JUnit (foo si blocca con il metamodello, la barra è a posto con la solita Query.

MODIFICA 5:

Dovresti essere in grado di riprodurre il problema scaricando il tarball , creando il progetto:

 ant compile or ant dist 

e avviare il test JUnit net.wazari.dao.test.TestMetaModel

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

(modifica runTest.sh per puntare CLASSPATH nella giusta posizione del tuo JUnit4-5 jar)

Tutte le dipendenze di ibernazione che uso dovrebbero essere incluse nell’archivio.

Ho avuto lo stesso problema ed è stato risolto inserendo la class Model e Model_ nello stesso pacchetto.

Ho avuto un’applicazione Java EE 6 usando EclipseLink su GlassFish con alcune classi @StaticMetamodel create e tutto funzionava bene. Quando sono passato a Hibernate 4 su JBoss 7, ho iniziato a ricevere anche questi NPE. Ho iniziato a indagare e ho trovato questa pagina:

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

Cita la specifica JPA 2, sezione 6.2.1.1 che definisce come devono essere costruite le classi statiche di metamodello. Ad esempio, ho scoperto leggendo la specifica che “l’opzione di pacchetti diversi sarà fornita in una versione futura di questa specifica”. Ho avuto le classi metamodel in diversi pacchetti e ha funzionato bene su EclipseLink, ma è una funzionalità extra, in quanto lo standard corrente indica quanto segue:

  • Le classi Metamodel dovrebbero essere nello stesso pacchetto delle classi di entity framework che descrivono;
  • Dovrebbero avere lo stesso nome delle classi di quadro che descrivono, seguito da un carattere di sottolineatura (ad esempio Prodotto è l’ quadro, Product_ è la class metamodel);
  • Se un’ quadro eredita da un’altra entity framework o da una superclass mappata, la sua class metamodel dovrebbe ereditare dalla class metamodel che descrive la sua superclass immediata (ad esempio se SpecialProduct estende il Prodotto, che estende PersistentObject, allora SpecialProduct_ dovrebbe estendere il Prodotto_ che dovrebbe estendere PersistentObject_).

Una volta che ho seguito tutte le regole nelle specifiche (il precedente è solo un riepilogo, fai riferimento alla sezione 6.2.1.1 delle specifiche per la versione completa), ho smesso di ottenere le eccezioni.

A proposito, puoi scaricare la specifica qui: http://jcp.org/en/jsr/detail?id=317 (fai clic su “Download page” per la versione finale, scegli di scaricare la specifica per la valutazione, accetta il accordo e scaricare il file “SR-000317 2.0 Specification” – persistence-2_0-final-spec.pdf).

Non riesco a riprodurre il problema. Ho usato alcune delle tue quadro (versioni semplificate di JPAAlbum , JPATheme e JPATagTheme , senza alcuna interfaccia), generato le classi metamodel e il seguente metodo di test rudimentale (eseguito all’interno di una transazione) passa semplicemente:

 @Test public void foo() { CriteriaBuilder builder = em.getCriteriaBuilder(); CriteriaQuery query = builder.createQuery(JPAAlbum.class); Root 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 results = em.createQuery(query).getResultList(); } 

FWIW, ecco l’SQL generato:

 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 

Testato con Hibernate EntityManager 3.5.6-Final, Hibernate JPAModelGen 1.1.0.Final, all’esterno di qualsiasi contenitore.

Il mio suggerimento sarebbe di provare prima a riprodurre (se riproducibile) il problema in un contesto di test JUnit.

PS: Come nota a margine, non memorizzerei le classi generate nel VCS.


Aggiornamento: ecco un persistence.xml che puoi usare in un contesto di test:

    org.hibernate.ejb.HibernatePersistence com.stackoverflow.q3854687.JPAAlbum com.stackoverflow.q3854687.JPATheme com.stackoverflow.q3854687.JPATagTheme true               

Offro una soluzione alternativa se il modello e il modello_ nello stesso pacchetto non funzionano. È necessario aggiungere un metodo init () alla class che crea SessionFactory o 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 } 

Pertanto, quando si esegue l’applicazione dal metodo principale o da un test di unità, è necessario chiamare HibernateSessionFactory.init(); primo. Quindi NullPointerException scompare magicamente e l’applicazione funziona.

Questo strano comportamento sembra accadere quando si passa un SingularAttribute giro tramite il parametro method.

Il credito va a @Can ÜNSAL che ha capito tutto in questa domanda: Hibernate / JPA – NullPointerException quando si accede al parametro SingularAttribute

Per NullPointerException , ho riscontrato un caso in cui Hibernate crea un attributo metamodel ma non lo inizializza mai, portando a una NullPointerException quando si tenta di usarlo.

 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 genera una dichiarazione di attributo di label in entrambe le classi:

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

… e inizializzerà Upper_.label ma lascerà Lower_.label uguale a null.

Boom .

La class e il metaModel dovrebbero essere nello stesso pacchetto, cioè

Entità cartella:

  • Eje
  • Eje_
  • Elemento
  • Elemento_

Ho allegato un esempio del codice metamodel

 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 id; public static volatile SingularAttribute name; public static volatile SingularAttribute users; public static volatile SingularAttribute createdAt; public static volatile SingularAttribute updatedAt; public static volatile SetAttribute factorCriticos; }