java - Hibernate 代理对象不适用于父类(super class)方法

标签 java hibernate javassist mappedsuperclass

我们有一个使用 Hibernate 的 Web 应用程序。将代码库升级到 Hibernate 3.6(从 3.3.2)后,我发现 Hibernate 生成的代理数据对象只为某些方法返回正确的值。似乎具体数据模型类中的方法工作正常,但 @MappedSuperclass 中的方法抽象父类(super class)不起作用。

这是我们的数据模型:

@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() 都运行良好。

谁能解释为什么会这样?这是映射父类(super class)的根本问题,还是有其他原因导致这种情况发生?

请注意 Form Hibernate 返回的对象是一个 Javassist 代理——如果在调试器中查看它通常有一个类似 Form_$$_javassist_15 的类名。等


更新:

这个问题似乎发生在 Hibernate 中,而不是 Javassist。我通过设置 hibernate.bytecode.provider=cglib 将字节码生成切换到 CGLIB在 hibernate.properties 中,但是使用 CGLIB 得到完全相同的错误结果(并确认 CGLIB 正在工作,因为 Hibernate 返回的类名变为 Form$$EnhancerByCGLIB$$4f3b4523 )。

不过,我仍然无法确定它出错的原因。

最佳答案

我找到了答案:父类(super class)中的一些 getter 和 setter 被标记为 final

事后看来,这是显而易见的……因为这些方法是最终的,代理类无法覆盖它们。所以解决方案是从映射父类(super class)中的任何 getter 和 setter 中删除 final

以下是在 SecuredDataObject 上定义的 getter 和 setter:

@MappedSuperclass
public abstract class SecuredDataObject extends DataObject {

    @Version
    @Column(name = "Version")
    private int version;

    @Basic
    @Column(name = "SecurityId", nullable = true)
    private Integer securityId;

    // Note - method IS NOT final
    public Integer getSecurityId() {
        return securityId;
    }

    public void setSecurityId(Integer securityId) {
        this.securityId = securityId;
    }   

    // Note - method IS final
    public final int getVersion() {
        return version;
    }

    public final void setVersion(final int version) {
        this.version = version;
    }
}

它解释了为什么我的测试正确返回 securityId 但没有正确返回 versiongetVersion()finalgetSecurityId() 不是。

总而言之,如果 Hibernate 可能尝试代理它们,请不要将您的 getter 和 setter 标记为 final!

关于java - Hibernate 代理对象不适用于父类(super class)方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4677613/

相关文章:

java - 为什么ExecutorService在执行HashMap操作时会死锁?

java - ORA-00942 : table or view does not exist - Hibernate with non-capital letters

java - 如何使用 JPA 锁定数据库行

android - 如何在Android项目中使用Javassist?

java - 获取 Javassist 类型而不是实际的 Hibernate 实体类型

java - android 在运行时替换方法调用

java - Android Studio mailto Intent 不显示主题和邮件正文

java - 在 Eclipse Workspace 中查找最常用的 Java 方法

java - 初始化方法以在 fragment 中注册 wifip2p 框架

java - 如何在 Hibernate 中放置自定义类型