У меня проблема с @MapsId
аннотацией и @EmbeddedId
. При запуске кода в Hibernate я получаю:
Причина: org.hibernate.PropertyAccessException: не удалось установить
значение поля с помощью установки отражения
com.test.entities.EmployeeId.serverId
Но давайте начнем с самого начала ... У меня есть составной первичный ключ для сущности Employee
, который состоит из внешних ключей для двух других сущностей (Server
и Website
). Чтобы иметь чистый дизайн, я использую отношения сущностей в сущности Сотрудника, которые должны быть отражены в встраиваемом элементе EmployeeId
. Пример довольно прост и выглядит следующим образом:
@Entity
public class Server implements Serializable {
@Id
@GeneratedValue
private int id;
private String url;
public Server() {}
public Server(String name) {
this.url = name;
}
}
@Entity
public class Website implements Serializable {
@Id
@GeneratedValue
private int id;
private String name;
public Website() {}
public Website(String name) {
this.name = name;
}
}
@Embeddable
public class EmployeeId implements Serializable {
protected int websiteId;
protected int serverId;
}
@Entity
public class Employee implements Serializable {
@EmbeddedId
private EmployeeId id;
private String firstName;
@ManyToOne
@MapsId("serverId")
private Server server;
@OneToOne
@MapsId("websiteId")
private Website website;
public Employee() {}
public Employee(String firstName, Server server, Website website) {
this.firstName = firstName;
this.server = server;
this.website = website;
}
}
Теперь у меня есть простой метод тестирования, написанный на Java SE (обратите внимание, что это обычный класс, выполняемый из статического основного метода - это , а не класс JUnit):
private void executeTest() {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("standaloneTests");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
Server s = new Server("BigServer");
em.persist(s);
Website w = new Website("domain.com");
em.persist(w);
Employee e = new Employee("John", s, w);
em.persist(e);
tx.commit();
em.close();
emf.close();
}
Как вы можете видеть, я не делаю здесь ничего необычного - просто установите сущности в объекте Employee
и сохраните его. Как я понимаю, аннотация @MapsId
должна отражать состояние аннотированной сущности в EmbeddedId
.
Теперь проблема в том, что в EclipseLink все работает гладко и сущности сохраняются должным образом. Когда я меняю провайдера JPA 2.0 на Hibernate (4.0 CR5), он выдает PropertyAccessException :
Исключение в потоке "main" javax.persistence.PersistenceException:
org.hibernate.PropertyAccessException: не удалось установить значение поля
установка отражения com.test.entities.EmployeeId.serverId в
org.hibernate.ejb.AbstractEntityManagerImpl.convert (AbstractEntityManagerImpl.java:1353)
в
org.hibernate.ejb.AbstractEntityManagerImpl.convert (AbstractEntityManagerImpl.java:1281)
в
org.hibernate.ejb.AbstractEntityManagerImpl.convert (AbstractEntityManagerImpl.java:1287)
в
org.hibernate.ejb.AbstractEntityManagerImpl.persist (AbstractEntityManagerImpl.java:853)
на com.test.Standalone.executeTest (Standalone.java:101) на
com.test.Standalone.main (Standalone.java:35) Причина:
org.hibernate.PropertyAccessException: не удалось установить значение поля
установка отражения com.test.entities.EmployeeId.serverId в
org.hibernate.property.DirectPropertyAccessor $ DirectSetter.set (DirectPropertyAccessor.java:150)
в
org.hibernate.mapping.Component $ ValueGenerationPlan.execute (Component.java:436)
в
org.hibernate.id.CompositeNestedGeneratedValueGenerator.generate (CompositeNestedGeneratedValueGenerator.java:121)
в
org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId (AbstractSaveEventListener.java:120)
в
org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId (EJB3PersistEventListener.java:78)
в
org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient (DefaultPersistEventListener.java:180)
в
org.hibernate.event.internal.DefaultPersistEventListener.onPersist (DefaultPersistEventListener.java:136)
в
org.hibernate.event.internal.DefaultPersistEventListener.onPersist (DefaultPersistEventListener.java:64)
в
org.hibernate.internal.SessionImpl.firePersist (SessionImpl.java:729)
в org.hibernate.internal.SessionImpl.persist (SessionImpl.java:705)
в org.hibernate.internal.SessionImpl.persist (SessionImpl.java:709)
в
org.hibernate.ejb.AbstractEntityManagerImpl.persist (AbstractEntityManagerImpl.java:847)
... еще 2 Причины: java.lang.NullPointerException at
sun.reflect.UnsafeFieldAccessorImpl.ensureObj (UnsafeFieldAccessorImpl.java:36)
в
sun.reflect.UnsafeIntegerFieldAccessorImpl.set (UnsafeIntegerFieldAccessorImpl.java:57)
в java.lang.reflect.Field.set (Field.java:657) в
org.hibernate.property.DirectPropertyAccessor $ DirectSetter.set (DirectPropertyAccessor.java:138)
... еще 13
Я не знаю, откуда может появиться исключение NullPointerException - как вы можете видеть, все свойства сущности установлены.
Я даже не знаю , зачем Hibernate нужен установщик , но просто чтобы убедиться, что я предоставил установщики для каждого поля (включая идентификаторы) для Employee
, Website
и Server
сущностей.Как и ожидалось - ничего не изменилось, и Hibernate все еще не может найти (уже присутствует) сеттер.
Как вы думаете, это может быть какая-то ошибка или я просто не понял какую-то часть контракта JPA 2.0?
Заранее спасибо!