3

Hibernateを使用するWebアプリケーションがあります。コードベースをHibernate3.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

}

これはHibernate3.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

これらのメソッドのうち4つが誤った結果を返しました:getId()、getVersion()、getLastUpdateDate()、およびgetCreatedDate()が0またはnullを返しました。データベースの実際の行には、ゼロ以外/ヌル以外の値があります。ただし、getName()、getPath()、および最も不思議なことにgetSecurityId()は正常に機能しました。

なぜこれが起こっているのか誰かが説明できますか?マップされたスーパークラスの根本的な問題ですか、それともこれが発生する可能性がある別の理由がありますか?

FormHibernateによって返されるオブジェクトはJavassistプロキシであることに注意してください。デバッガーで表示すると、通常、Form_$$_javassist_15などのようなクラス名が付けられます。


アップデート:

この問題は、JavassistではなくHibernateで発生しているようです。hibernate.propertiesで設定してバイトコード生成をCGLIBに切り替えましたが、CGLIBを配置しhibernate.bytecode.provider=cglibてもまったく同じ誤った結果が得られます(Hibernateによって返されるクラス名がになるためCGLIBが機能していることを確認しましたForm$$EnhancerByCGLIB$$4f3b4523)。

しかし、なぜそれがうまくいかないのかを特定することにはまだ近づいていません。

4

1 に答える 1

4

私は答えを見つけました:スーパークラスのゲッターとセッターのいくつかはマークされていましたfinal

後から考えると、これは明らかです...メソッドが最終的なものであるため、プロキシクラスはそれらをオーバーライドできませんでした。したがって、解決策は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()たのfinalに対し、getSecurityId()そうではありませんでした。

したがって、要約するとfinal、Hibernateがそれらをプロキシしようとするかのように、ゲッターとセッターにマークを付けないでください。

于 2011-01-14T01:29:27.117 に答える