У меня проблема с аннотацией @MapsId
и @EmbeddedId
. При запуске кода в Hibernate я получаю:
Вызвано: org.hibernate.PropertyAccessException: не удалось установить значение поля установщиком отражения com.test.entities.EmployeeId.serverId
Но, давайте начнем с самого начала ...У меня есть составной первичный ключ для объекта Сотрудник
, который состоит из внешних ключей для двух других объектов ( Сервер
и Веб-сайт
). Чтобы иметь чистый дизайн, я использую отношения сущностей в сущности Employee, которые должны быть отражены во встраиваемом файле 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 :
Exception in thread "main" javax.persistence.PersistenceException: org.hibernate.PropertyAccessException : не удалось установить значение поля с помощью установщика отражения com.test.entities.EmployeeId.serverId в org.hibernate.ejb.AbstractEntityManagerImpl.convert (AbstractEntityManagerImpl.java:1353) {{1 }} в org.hibernate.ejb.AbstractEntityManagerImpl.convert (AbstractEntityManagerImpl.java:1281) в org.hibernate.ejb.AbstractEntityManagerImpl.convert (AbstractEntityManager:12Impl.java ) в org.hibernate.ejb.AbstractEntityManagerImpl.persist (AbstractEntityManagerImpl.java: 853) в com.test.Standalone.executeTest (Standalone.java:101) в com.test.Standalone.main (Standalone.java:35) Причина: {{1 }} 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} в {1: }} org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId (EJB3PersistEventListener.java:78) в org.hibernate.event.internal.DefaultPersistEventListener.entityIs80_Transient (DefaultListenerIs) { {1}} в org.hibernate.event.int ernal.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 в 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 нужен сеттер , но на всякий случай я предоставил сеттеры для каждого поля (включая идентификаторы) для Сотрудника
, Веб-сайт
и Сервер
сущности. Как и ожидалось - ничего не изменилось, и Hibernate все еще не может найти (уже существующий) установщик.
Как вы думаете, это может быть ошибка или я просто не понял какую-то часть контракта JPA 2.0?
Заранее спасибо!