JPA/Hibernate Static Metamodel Attributes not Populated -- NullPointerException

22,696

Solution 1

I had the same issue and it was fixed by putting the Model and Model_ class into the same package.

Solution 2

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).

Solution 3

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>

Solution 4

2019-04-24

The usual issue for unpopulated metamodel class attributes, is when the metamodel classes are in a different package than the corresponding managed classes.

The latest, JPA 2.2 specification still requires to have your metamodel classes in the same package as your corresponding managed classes.

Reference: Page 238, §6.2.1.1 Canonical Metamodel

Solution 5

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

Share:
22,696

Related videos on Youtube

Kevin
Author by

Kevin

I just complete my PhD program with the University of Grenoble and STMicroelectronics, in which I proposed a new dimension for interactive debugging, based on the programming model and runtime environments used to develop the application. I am a Free &amp; Open Source Software enthusiast, I did my all PhD work with free tools (GNU/Linux OS, Emacs, LaTeX, GCC, ...) and contributed code patches to GDB, the debugger of the GNU project.

Updated on July 09, 2022

Comments

  • Kevin
    Kevin almost 2 years

    I would like to use JPA2 Criteria API with metamodel objects, which seems to be pretty easy:

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

    but this Root.get always throws a NullPointerException. JPAAlbum_.theme was automatically generated by Hibernate and looks like

    public static volatile SingularAttribute<JPAAlbum, JPATheme> theme;
    

    but it's obviously never populated.

    Am I missing a step in the initialization of the framework ?

    EDIT: here is a snippet of how I use JPA and the metamodel when it's crashing:

        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_ is a class, so I just import before) and the associated stacktrace:

    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:

    In the JBoss EntityManager guide, I can see that

    When the Hibernate EntityManagerFactory is being built, it will look for a canonical metamodel class for each of the managed typed is knows about and if it finds any it will inject the appropriate metamodel information into them, as outlined in [JPA 2 Specification, section 6.2.2, pg 200]

    I could also verify with

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

    that Hibernate is aware of my metamodel, the attribute names are written, however

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

    remains desperately empty ...

    EDIT3: here is the JPAAlbum entity and its metamodel class.

    What else can I tell about my configuration ...

    • I use Hibernat 3.5.6-Final (according to META-INF/MANIFEST.MF),

    • deploy on Glassfish 3.0.1

    • from Netbeans 6.9.1;

    • and the application relies on EJB 3.1,

    I hope it will help !

    EDIT 4:

    unfortunately, the JUnit test leads to the same 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)
    

    A much simpler project is available here/tarball. It only contains my entities and their metamodel, plus a JUnit test (foo crashes with metamodel, bar is okay with the usual Query.

    EDIT 5:

    You should be able to reproduce the problem by downloading the tarball, building the project:

    ant compile
    or
    ant dist
    

    and start the JUnit test net.wazari.dao.test.TestMetaModel

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

    (edit runTest.sh to point CLASSPATH to the right location of your JUnit4-5 jar)

    All the hibernate dependencies I use should be included in the archive.

    • Devanshu Mevada
      Devanshu Mevada over 13 years
      Please show your whole code snippet (I don't understand how you use the metamodel) and the stacktrace.
    • Kevin
      Kevin over 13 years
      @Pascal Thivent, I've updated the question with what you asked for, thanks
    • Devanshu Mevada
      Devanshu Mevada over 13 years
      Can you show your entity so that I could reproduce?
    • Kevin
      Kevin over 13 years
      @Pascal I've update the question
    • Kevin
      Kevin about 13 years
      @Pascal, just FYI, the question, which is quite likely to be a bug, has been solved !
  • Kevin
    Kevin over 13 years
    I'm trying to test it in JUnit, but my entity class are not recognized by Hibernate 'IllegalArgumentException: Not an entity: class ...JPAAlbum' (in your 'from' method) or 'NoResultException: No entity found for query' (in the usual Query.getSingleResult();)
  • Kevin
    Kevin over 13 years
    'I wouldn't store generated classes' My idea is 1) to keep the VCS is in error-free state, 2) update manually the entities/metamodels as soon as a do a minor-because-the-db-structure-is-now-quite-stable update, is it a bad idea?
  • Devanshu Mevada
    Devanshu Mevada over 13 years
    @Kevin Hmm, did you declare your entities in a persistence.xml (in a Java SE context, they aren't automatically discovered, you need to list them explicitly)? Actually, the whole persistence.xml will be different. I'll post an example.
  • Devanshu Mevada
    Devanshu Mevada over 13 years
    @Kevin Regarding your VCS approach, if you derive B from A in a deterministic way, then having A in a stable state is enough. But I wouldn't call storing B a bad idea, it's just a different approach. Some people like to store generated code, some others prefer to keep the generation step as a build activity only. In the former case, you can get the sources and you're ready. But you have to commit generated code after each change. In the later case, you need a generation step before to compile. It's debatable but I prefer the later approach :)
  • Kevin
    Kevin over 13 years
    @Pascal, I've updated the question, the JUnit test fails as well, what else could I try ... ?
  • Devanshu Mevada
    Devanshu Mevada over 13 years
    @Kevin Well, it's actually good that the JUnit test is failing. At least this means the problem is reproducible. I'd like to have a look but I couldn't find how to do an anonymous checkout from your svn repository. Did I miss the instructions?
  • Kevin
    Kevin over 13 years
    @Pascal, sorry, I added a link to a tar'ed version that you should be able to reproduce. (your right that JUnit failing is actually a luck, I didn't see it this way :)
  • Kevin
    Kevin over 13 years
    @Pascal, thanks for your help, you deserve the bounty! feel free to let me know if you've got any further clue about what can be wrong, I'll give it a try !
  • Devanshu Mevada
    Devanshu Mevada over 13 years
    @Kevin Thank you, that's nice from you. I only had a quick look at your code but didn't had the opportunity to test it for now (I'll do!), mostly because the JUnit test doesn't run "as is". I just noticed you don't have any jar of a JPA provider in the libs, in that normal? I'm afraid I'll have to move your code to a Maven project, I'm not very patient with Ant and JAR hell :)
  • Kevin
    Kevin over 13 years
    @Pascal, I've updated the tarball to contain all the required JARs, it should be easier for you to reproduce the situation (Maven might be one of the next step for my project!)
  • Kevin
    Kevin about 13 years
    it gives some hopes, but I'm afraid that when I built the test case for Pascal, everything should have been in the same package ... I'll check that this evening !
  • Kevin
    Kevin about 13 years
    I can't believe it, that's the solution !! Thank you very much for this so valuable little hint ;)
  • Benjamin Seiller
    Benjamin Seiller almost 12 years
    +1 Had pretty much the same problem while using Eclipselink instead of Hibernate, which initially just worked fine & then stopped doing so - same package, of course...
  • Chris Betti
    Chris Betti over 10 years
    One more note about MappedSuperclass not mentioned in the Hibernate spec: when extending the base metamodel, you should not redefine the parameters defined in the base in your subclass.
  • Pasha GR
    Pasha GR over 6 years
    great job @Vítor E. Silva Souza!
  • Vítor E. Silva Souza
    Vítor E. Silva Souza over 6 years
    Thanks, @PashaGharibi!
  • Khalid Shah
    Khalid Shah almost 6 years
    can someone explain little bit more about how you add classes in same package ? the same package in which all other entity classes are ? have any hibernate annotation put on these classes ?