【发布时间】:2011-12-20 12:37:03
【问题描述】:
@MapsId 注释和@EmbeddedId 有问题。在 Hibernate 中运行代码时,我得到:
原因:org.hibernate.PropertyAccessException:无法设置 通过反射设置器的字段值 com.test.entities.EmployeeId.serverId
但是,让我们从头开始...我有一个实体 Employee 的复合主键,它由两个其他实体(Server 和 Website)的外键组成。为了有一个干净的设计,我在 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 编写的简单测试方法(注意这是从静态 main 方法执行的常规类 - 它不是 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:
线程“主”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 需要一个 setter,但为了确保我已经为 Employee、Website 和 Website 的每个字段(包括 ID)提供了 setter Server 实体。正如预期的那样——没有任何改变,Hibernate 仍然找不到(已经存在的)setter。
您认为这可能是一些错误还是我只是不理解 JPA 2.0 合同的某些部分?
提前致谢!
【问题讨论】:
标签: hibernate jpa jpa-2.0 eclipselink