2011-01-13 11 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でOK働いたが、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を返しました。データベースの実際の行には、非ゼロ/非NULL値があります。しかし、getName()、getPath()、そして最も不思議なことにgetSecurityId()はうまくいきました。

これはなぜ起こっているのですか?それはマップされたスーパークラスの根本的な問題か、これが起こる別の理由がありますか?

Hibernateが返さFormオブジェクトはJavassistのプロキシであることに注意してください - デバッガで見ると、それは一般的にForm_$$_javassist_15のようなクラス名を持つなど


更新:この問題は、と思わ

Javassistではなく、Hibernateで発生している可能性があります。私は、hibernate.propertiesにhibernate.bytecode.provider=cglibを設定してバイトコード生成をCGLIBに切り替えましたが、CGLIBを使って同じ結果を得ることができました(Hibernateから返されたクラス名がForm$$EnhancerByCGLIB$$4f3b4523になったためCGLIBが動作しています)。

私はまだそれが間違っている理由を特定することにはまだ近いです。

+0

おそらく、バグレポートを提出する必要があります。この予期しない動作を証明するテストがあり、そのテストをHibernateだけに分けた場合、これはバグレポートの良い候補です。通常、Hibernateのチームはあなたに "テストを提供して証明する"と挑戦します:) – chris

+0

ゲッターとセッターの中には最終的なものがあったので、私は自分の責任でした。しかし、私はHibernateのドキュメントでこれを行うことに関する警告を見つけることができなかったので、ドキュメントの問題を報告するかもしれません。ドキュメントは最終的なクラスについて警告しますが、最終的なメソッドについては警告しません... – gutch

答えて

3

私は答えを見つけました:スーパークラスのgetterとsetterのいくつかはfinalとマークされています。

これは明らかです。メソッドが最終的なので、プロキシクラスはそれらをオーバーライドできませんでした。だから解決策は、マップされたスーパークラスのgetterとsetterからfinalを削除することです。ここで

SecuredDataObject上で定義されたゲッターとセッターです:

@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()getSecurityId()ではなかったのに対し、finalました。

要約すると、Hibernateがプロキシを試行する可能性がある場合は、ゲッターとセッターをfinalとマークしないでください。

関連する問題