Подтвердить что ты не робот

JPA/Hibernate Static Metamodel Атрибуты не заполнены - NullPointerException

Я хотел бы использовать API-интерфейс JPA2 с объектами метамодели, что кажется довольно простым:

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

но этот Root.get всегда выбрасывает NullPointerException. JPAAlbum_.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 и метамодель.

Что еще я могу рассказать о моей конфигурации...

  • Я использую Hibernat 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)

Доступен гораздо более простой проект здесь/tarball. Он содержит только мои сущности и их метамодель плюс тест JUnit (сбой foo с метамоделью, 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)

Все связанные с гибернацией зависимости должны быть включены в архив.

4b9b3361

Ответ 1

У меня была такая же проблема, и она была исправлена, поместив класс Model и Model_ в один и тот же пакет.

Ответ 2

У меня было приложение Java EE 6 с использованием EclipseLink на GlassFish с некоторыми классами @StaticMetamodel, созданными и все работало нормально. Когда я переключился на Hibernate 4 на JBoss 7, я начал получать эти 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_ должен расширять Product_, который должен расширять PersistentObject_).

Как только я выполнил все правила в спецификации (приведенное выше просто сводка, см. раздел 6.2.1.1 спецификации для полной версии), я прекратил получать исключения.

Кстати, вы можете скачать спецификацию здесь: http://jcp.org/en/jsr/detail?id=317 (нажмите "Загрузить страницу" для окончательной версии, выберите загрузить спецификацию для оценки, принять соглашение и загрузить файл "SR-000317 2.0 Specification" - persistence-2_0-final-spec.pdf).

Ответ 3

Я не могу воспроизвести проблему. Я использовал некоторые из ваших сущностей (упрощенные версии 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, вот сгенерированный 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>

Ответ 4

Я предлагаю альтернативное решение, если установка модели и модели в том же пакете не работает. Вам нужно добавить один метод init() в ваш класс, который создает SessionFactory или 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
}

Поэтому, когда вы запускаете приложение из основного метода или unit test, сначала нужно вызвать HibernateSessionFactory.init();. Затем NullPointerException волшебным образом исчезает и приложение работает.

Это странное поведение, похоже, происходит, когда вы передаете SingularAttribute через параметр метода.

Кредит отправляется @Can ÜNSAL, который решил все это в этом вопросе: Hibernate/JPA - исключение NullPointerException при доступе к параметру SingularAttribute