JPA / Hibernate静态元模型属性未填充 - NullPointerException

问题描述 投票:22回答:8

我想将JPA2 Criteria API与元模型对象一起使用,这看起来很简单:

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

但是这个Root.get总是抛出一个NullPointerExceptionJPAAlbum_.theme是由Hibernate自动生成的,看起来像

public static volatile SingularAttribute<JPAAlbum, JPATheme> theme;

但它显然从未填充过。

我错过了框架初始化的一个步骤吗?

编辑:这是我在崩溃时如何使用JPA和元模型的片段:

    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_是一个类,所以我之前只是import)和相关的堆栈跟踪:

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)

编辑2:

在JBoss EntityManager指南中,我可以看到

当构建Hibernate EntityManagerFactory时,它将查找每个托管类型的规范元模型类,如果它找到任何它将向它们注入适当的元模型信息,如[JPA 2规范,第6.2节中所述] .2,页码200]

我也可以验证

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

但是,Hibernate知道我的元模型,但是编写了属性名称

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

仍然绝望地空着......

EDIT3:这是JPAAlbum entity及其metamodel class

关于我的配置我还能说些什么......

  • 我使用Hibernate 3.5.6-Final(根据META-INF / MANIFEST.MF),
  • 部署在Glassfish 3.0.1上
  • 来自Netbeans 6.9.1;
  • 并且应用程序依赖于EJB 3.1,

我希望它会有所帮助!

编辑4:

不幸的是,JUnit测试导致了同样的异常:

java.lang.NullPointerException
    at org.hibernate.ejb.criteria.path.AbstractPathImpl.get(AbstractPathImpl.java:138)
    at net.wazari.dao.test.TestMetaModel.foo(TestMetaModel.java:55)

一个更简单的项目是here / tarball。它只包含我的实体和他们的元模型,加上一个JUnit测试(foo与metamodel崩溃,bar可以使用通常的Query。

编辑5:

您应该能够通过下载tarball来重现问题,构建项目:

ant compile
or
ant dist

并启动JUnit测试net.wazari.dao.test.TestMetaModel

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

(编辑runTest.sh将CLASSPATH指向JUnit4-5 jar的正确位置)

我使用的所有hibernate依赖项都应该包含在归档中。

java hibernate nullpointerexception jpa-2.0 criteria-api
8个回答
46
投票

我有同样的问题,并通过将ModelModel_类放入同一个包中来解决。


10
投票

我在GlassFish上使用EclipseLink创建了一个Java EE 6应用程序,并创建了一些@StaticMetamodel类,一切正常。当我在JBoss 7上切换到Hibernate 4时,我也开始使用这些NPE。我开始调查,我找到了这个页面:

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

它引用了JPA 2规范,第6.2.1.1节,它定义了如何构建静态元模型类。例如,我通过阅读规范发现“将在本规范的未来版本中提供不同包的选项”。我在不同的包中使用了元模型类,它在EclipseLink上运行良好,但它是一个额外的功能,因为当前标准表明如下:

  • 元模型类应与它们描述的实体类位于同一个包中;
  • 它们应该与它们描述的实体类具有相同的名称,后跟下划线(例如,Product是实体,Product_是元模型类);
  • 如果实体继承自另一个实体或映射的超类,则其元模型类应继承描述其直接超类的元模型类(例如,如果SpecialProduct扩展了Product,它扩展了PersistentObject,那么SpecialProduct_应该扩展应该扩展PersistentObject_的Product_)。

一旦我遵循规范中的所有规则(上面只是一个摘要,请参阅完整版本规范的第6.2.1.1节),我就停止了例外。

顺便提一下,你可以在这里下载规范:http://jcp.org/en/jsr/detail?id=317(点击“下载页面”获取最终版本,选择下载评估规范,接受协议并下载文件“SR-000317 2.0规范” - persistence-2_0 -Final-spec.pdf)。


8
投票

我无法重现这个问题。我使用了你的一些实体(简化版本的JPAAlbumJPAThemeJPATagTheme,没有任何接口),生成了元模型类和以下基本测试方法(在事务中运行)只传递:

@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,这是生成的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

在任何容器外部使用Hibernate EntityManager 3.5.6-Final,Hibernate JPAModelGen 1.1.0.Final进行测试。

我的建议是首先尝试在JUnit测试上下文中重现(如果可重现)问题。

PS:作为旁注,我不会在VCS中存储生成的类。


更新:这是一个persistence.xml,你可以在测试环境中使用:

<?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>

0
投票

如果将Model和Model_放在同一个包中不起作用,我会提供替代解决方案。您需要向构建SessionFactory或EntityManager的类添加一个init()方法:

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
}

因此,当您从main方法或单元测试运行应用程序时,您需要先调用HibernateSessionFactory.init();。然后NullPointerException神奇地消失,应用程序工作。

当您通过方法参数传递SingularAttribute时,似乎会发生这种奇怪的行为。

归功于@CanÜNSAL,他在这个问题中全力以赴:Hibernate/JPA - NullPointerException when accessing SingularAttribute parameter


0
投票

仅供参考,我遇到过Hibernate创建元模型属性但从未初始化它的情况,在尝试使用它时会导致NullPointerException

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在两个类中生成label属性声明:

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

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

...它会初始化Upper_.label但是让Lower_.label等于null。

繁荣。


0
投票

类和metaModel应该在同一个包中,即

文件夹实体:

  • Eje_
  • 元件
  • 元件_

我附上了元模型代码的一个例子

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<Eje, Integer> id;
    public static volatile SingularAttribute<Eje, String> name;
    public static volatile SingularAttribute<Eje, Integer> users;
    public static volatile SingularAttribute<Eje, Date> createdAt;
    public static volatile SingularAttribute<Eje, Date> updatedAt;
    public static volatile SetAttribute<Eje, FactorCritico> factorCriticos;
}

0
投票

如果上述任何内容都无法解决此NPE问题,您还可以检查是否在实体关系中使用List而不是Set。

我发现使用List需要在元模型中声明ListAttribute而不是SetAttribute,否则,它会引发NullPointerException,如果你没有看到整个堆栈跟踪,你将不会注意到你的JPA规范没有初始化元模型。


0
投票

2019-04-24

无填充元模型类属性的常见问题是,元模型类与相应的托管类位于不同的包中。

最新的JPA 2.2规范仍然要求将元模型类与相应的托管类放在同一个包中。

Reference:第238页,§6.2.1.1规范元模型

© www.soinside.com 2019 - 2024. All rights reserved.