【发布时间】:2011-01-13 07:06:47
【问题描述】:
我们有一个使用 Hibernate 的 Web 应用程序。将代码库升级到 Hibernate 3.6(从 3.3.2)后,我发现 Hibernate 生成的代理数据对象只为某些方法返回正确的值。看起来具体数据模型类中的方法工作正常,但@MappedSuperclass 抽象超类中的方法不起作用。
这是我们拥有的数据模型:
@MappedSuperclass
public abstract class DataObject implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ID", unique = true, columnDefinition = "serial")
private int id;
// getter, setter, equals, hashcode implementations here
}
@MappedSuperclass
public abstract class SecuredDataObject extends DataObject {
@Version
@Column(name = "Version")
private int version;
@Basic
@Column(name = "SecurityId", nullable = true)
private Integer securityId;
// getters, setters here
}
@MappedSuperclass
public abstract class AuditedDataObject extends SecuredDataObject {
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "CreatedDate", nullable = true)
private Date createdDate;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "LastUpdateDate", nullable = true)
private Date lastUpdateDate;
// getters, setters here
}
@Entity
@Table(name = "Form")
public class Form extends AuditedDataObject {
@Basic
@Column(name = "Name", length = 200, nullable = false)
private String name;
@Basic
@Column(name = "Path", length = 80, nullable = true)
private String path;
// getters, setters, other properties and methods here
}
这在 Hibernate 3.3.2 中运行良好,但在升级到 Hibernate 3.6 后,应用程序出现了问题。下面的测试代码说明了这个问题:
int formId = 1234;
Form form = (Form) sessionFactory.getCurrentSession().load(Form.class, formId);
System.out.print("id = ");
System.out.println(formId);
System.out.print("getId() = ");
System.out.println(form.getId());
System.out.print("getSecurityId() = ");
System.out.println(form.getSecurityId());
System.out.print("getVersion() = ");
System.out.println(form.getVersion());
System.out.print("getLastUpdateDate() = ");
System.out.println(form.getLastUpdateDate());
System.out.print("getCreatedDate() = ");
System.out.println(form.getCreatedDate());
System.out.print("getName() = ");
System.out.println(form.getName());
System.out.print("getPath() = ");
System.out.println(form.getPath());
该代码的输出是:
id = 1234
getId() = 0
getSecurityId() = 182
getVersion() = 0
getLastUpdateDate() = null
getCreatedDate() = null
getName() = Form name here
getPath() = /path/here
其中四个方法返回了错误的结果:getId()、getVersion()、getLastUpdateDate() 和 getCreatedDate() 返回了 0 或 null。数据库中的实际行具有非零/非空值。但是 getName()、getPath() 和最奇怪的是 getSecurityId() 都可以正常工作。
谁能解释为什么会这样?这是映射超类的基本问题,还是有其他原因导致这种情况发生?
请注意,Hibernate 返回的 Form 对象是 Javassist 代理 - 如果在调试器中查看,它通常具有类似 Form_$$_javassist_15 等的类名。
更新:
这个问题似乎发生在 Hibernate 中,而不是 Javassist 中。我通过在 hibernate.properties 中设置 hibernate.bytecode.provider=cglib 将字节码生成切换到 CGLIB,但是在使用 CGLIB 时得到完全相同的错误结果(并确认 CGLIB 正在工作,因为 Hibernate 返回的类名变为 Form$$EnhancerByCGLIB$$4f3b4523)。
不过,我仍然无法确定它出错的原因。
【问题讨论】:
-
也许您需要提交错误报告。如果您有一个测试证明了这种意外行为,并且您只将该测试隔离到 Hibernate,那么这是一个很好的错误报告候选者。通常 Hibernate 团队会挑战你“通过提供测试来证明它”:)
-
我是我的错,因为有些 getter 和 setter 是
final。但是,我在 Hibernate 文档中找不到有关执行此操作的警告,因此我可能会报告文档问题。该文档确实警告了最终类,但没有警告最终方法...
标签: java hibernate javassist mappedsuperclass