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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3854687/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 03:42:10  来源:igfitidea点击:

JPA/Hibernate Static Metamodel Attributes not Populated -- NullPointerException

javahibernatenullpointerexceptionjpa-2.0criteria-api

提问by Kevin

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

我想将 JPA2 Criteria API 与元模型对象一起使用,这似乎很容易:

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

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

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

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:

编辑:这是我在崩溃时如何使用 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_is a class, so I just importbefore) and the associated stacktrace:

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

EDIT 2:

编辑2:

In the JBoss EntityManager guide, I can see that

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

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]

在构建 Hibernate EntityManagerFactory 时,它将为每个已知的托管类型查找规范的元模型类,如果找到,它将向其中注入适当的元模型信息,如 [JPA 2 规范,第 6.2 节中所述.2,第 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

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

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

remains desperately empty ...

仍然绝望地空虚......

EDIT3: here is the JPAAlbum entityand its metamodel class.

EDIT3:这里是JPAAlbum 实体及其元模型类

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,

  • 我使用 Hibernat 3.5.6-Final(根据 META-INF/MANIFEST.MF),

  • 在 Glassfish 3.0.1上部署

  • 来自 Netbeans 6.9.1

  • 并且应用程序依赖于 EJB 3.1

I hope it will help !

我希望它会有所帮助!

EDIT 4:

编辑 4:

unfortunately, the JUnit test leads to the same exception:

不幸的是,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)

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.

一个更简单的项目,请点击这里/压缩包它只包含我的实体和它们的元模型,以及一个 JUnit 测试(foo 与元模型崩溃,bar 与通常的 Query.

EDIT 5:

编辑 5:

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

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

ant compile
or
ant dist

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

并开始 JUnit 测试 net.wazari.dao.test.TestMetaModel

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

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

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

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

我使用的所有休眠依赖项都应该包含在存档中。

回答by debbie

I had the same issue and it was fixed by putting the Modeland Model_class into the same package.

我遇到了同样的问题,它通过将ModelModel_类放入同一个包中来解决。

回答by Vítor E. Silva Souza

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:

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

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

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:

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

  • 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_).
  • 元模型类应该和它们描述的实体类在同一个包中;
  • 它们应该与它们描述的实体类具有相同的名称,后跟一个下划线(例如,Product 是实体,Product_ 是元模型类);
  • 如果一个实体从另一个实体或映射的超类继承,它的元模型类应该从描述其直接超类的元模型类继承(例如,如果 SpecialProduct 扩展 Product,它扩展 PersistentObject,那么 SpecialProduct_ 应该扩展 Product_,它应该扩展 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.

一旦我遵循了规范中的所有规则(以上只是一个摘要,完整版本请参阅规范的第 6.2.1.1 节),我不再收到异常。

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

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

回答by Pascal Thivent

I can't reproduce the issue. I used some of your entities (simplified versions of JPAAlbum, JPAThemeand JPATagTheme, without any interfaces), generated the metamodel classes and the following rudimentary test method (running inside a transaction) just passes:

我无法重现该问题。我使用了您的一些实体(JPAAlbum,JPATheme和 的简化版本JPATagTheme,没有任何接口),生成了元模型类和以下基本测试方法(在事务中运行)刚刚通过:

@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:

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

Tested with Hibernate EntityManager 3.5.6-Final, Hibernate JPAModelGen 1.1.0.Final, outside any container.

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

My suggestion would be to first try to reproduce (if reproducible) the problem in a JUnit test context.

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

PS: As a side note, I wouldn't store generated classes in the VCS.

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



Update:Here is a persistence.xmlthat you can use in a testing context:

更新:这是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>

回答by EliteRaceElephant

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:

如果将 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
}

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.

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

This strange behaviour seems to happen when you pass a SingularAttributearound via method parameter.

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

Credit goes to @Can üNSAL who figured it all out in this question: Hibernate/JPA - NullPointerException when accessing SingularAttribute parameter

归功于@Can üNSAL,他在这个问题中解决了所有问题:Hibernate/JPA - NullPointerException when accessing SingularAttribute parameter

回答by Archie

FYI, I encountered a case where Hibernate creates a metamodel attribute but never initializes it, leading to a NullPointerException's when trying to use it.

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

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 generate a labelattribute declaration in bothclasses:

Hibernatelabel两个类中生成一个属性声明:

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

...and it will initialize Upper_.labelbut leave Lower_.labelequal to null.

...它会初始化Upper_.labelLower_.label等于null。

Boom.

繁荣

回答by Jorge Santos Neill

The class and the metaModel should be in the same package, i.e.

类和元模型应该在同一个包中,即

Folder entities:

文件夹实体:

  • Eje
  • Eje_
  • Element
  • Element_
  • 埃杰
  • Eje_
  • 元素
  • 元素_

I attached one example of the metamodel code

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

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

回答by Eduardo

If nothing of above resolve this NPE issue, you also can check whether you are using List in your Entities relationships instead of Set.

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

I found out that using List's it is needed to declare ListAttribute instead of SetAttribute in the metamodel, otherwise, it provoke a NullPointerException and if you don't see the whole stack trace you will not notice that the metamodel was not initialized by your JPA specification.

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

回答by Z3d4s

2019-04-24

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.2specification still requires to have your metamodel classes in the same package as your corresponding managed classes.

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

Reference: Page 238, §6.2.1.1 Canonical Metamodel

参考:第 238 页,第 6.2.1.1 节规范元模型