2011-01-13 46 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

相關問題