JPA/Hibernate Static Metamodel Attributes not Populated -- NullPointerException
I had the same issue and it was fixed by putting the Model
and Model_
class into the same package.
I had a Java EE 6 application using EclipseLink on GlassFish with some @StaticMetamodel classes created and everything was working fine. When I switched to Hibernate 4 on JBoss 7, I started getting these NPEs too. I started investigating and I found this page:
http://docs.jboss.org/hibernate/entitymanager/3.6/reference/en/html/metamodel.html
It quotes the JPA 2 specification, section 6.2.1.1 which defines how the static metamodel classes should be built. For example, I found out by reading the spec that "the option of different packages will be provided in a future release of this specification". I had the metamodel classes in different packages and it worked fine on EclipseLink, but it's an extra feature, as the current standard indicates the following:
- Metamodel classes should be in the same package as the entity classes they describe;
- They should have the same name as the entity classes they describe, followed by an underscore (e.g. Product is the entity, Product_ is the metamodel class);
- If an entity inherits from another entity or from a mapped superclass, its metamodel class should inherit from the metamodel class that describes its immediate superclass (e.g. if SpecialProduct extends Product, which extends PersistentObject, then SpecialProduct_ should extend Product_ which should extend PersistentObject_).
Once I followed all the rules in the spec (the above is just a summary, please refer to section 6.2.1.1 of the spec for the complete version), I stopped getting the exceptions.
By the way, you can download the specification here: http://jcp.org/en/jsr/detail?id=317 (click on "Download page" for the final release, choose to download the specification for evaluation, accept the agreement and download the file "SR-000317 2.0 Specification" - persistence-2_0-final-spec.pdf).
I can't reproduce the issue. I used some of your entities (simplified versions of JPAAlbum
, JPATheme
and JPATagTheme
, without any interfaces), generated the metamodel classes and the following rudimentary test method (running inside a transaction) just passes:
@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, here is the generated 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
Tested with Hibernate EntityManager 3.5.6-Final, Hibernate JPAModelGen 1.1.0.Final, outside any container.
My suggestion would be to first try to reproduce (if reproducible) the problem in a JUnit test context.
PS: As a side note, I wouldn't store generated classes in the VCS.
Update: Here is a persistence.xml
that you can use in a testing context:
<?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>
I offer an alternative solution if putting the Model and Model_ in the same package does not work. You need to add one init() method to your class that builds the SessionFactory or 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
}
So when you run your application from main method or a unit test you need to call HibernateSessionFactory.init();
first. Then the NullPointerException magically disappears and the application works.
This strange behaviour seems to happen when you pass a SingularAttribute
around via method parameter.
Credit goes to @Can ÜNSAL who figured it all out in this question: Hibernate/JPA - NullPointerException when accessing SingularAttribute parameter