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