2011-01-13 45 views
2

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

这是我们拥有的数据模型:

@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的工作确定,但升级后休眠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到位的情况下获得完全相同的错误结果(并且由于Hibernate返回的类名称变为Form$$EnhancerByCGLIB$$4f3b4523,所以确认CGLIB正在工作)。

尽管如此,我仍然没有接近确定为什么会出错。

+0

也许你需要提交一份错误报告。如果你有一个可以证明这种意外行为的测试,并且你只将测试隔离到Hibernate,那么这是一个很好的候选bug报告。通常Hibernate团队会挑战你“通过提供一个测试来证明它”:) – chris 2011-01-13 23:51:48

回答

3

我找到了答案:超类的一些getter和setter标记为final

事后看来,这是显而易见的......因为方法是最终的,代理类无法覆盖它们。所以解决方案是从映射超类中的任何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但没有正确返回version - getVersion()finalgetSecurityId()不是。

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

相关问题