まず、二つの規則:
- プロキシデリゲートすべて非最後の方法は、idのプロパティへのアクセスは、マッピングで定義されている場合は、idを取得するためのメソッドを除き、ターゲット・インスタンスへの呼び出し。
- プロキシオブジェクトのインスタンスがでない場合、が初期化され、ターゲットインスタンスが初期化されます。
1)両方a
とb
が同じエンティティのプロキシどこあなたがa.equals(b)
を呼び出すと仮定します。そしてequals
方法は次のように実装されていることを言うことができます:a
のequals
方法は、その完全な初期化を強制するターゲット・インスタンスに委譲され
public boolean equals(Object other) {
...
if (this.someField.equals(other.someField)) {
...
}
...
}
。したがって、a
インスタンスのフィールドについては安全です(直接使用できます)。
ただし、b
インスタンス(other.someField
)のフィールドに直接アクセスすると、は無効となります。は有効です。 b
が初期化されているかどうかは関係ありません。プロキシインスタンスは決して初期化されず、ターゲットインスタンスのみが初期化されます。したがって、someField
は、b
インスタンスでは常にnull
です。
this.someField.equals(other.getSomeField())
や一貫性を:: - Hibernateはできない、それはfinal
方法に来るとき
this.getSomeField().equals(other.getSomeField())
物事が異なっている
正しい実装はother
例えば少なくともゲッターを使用することですそれらをオーバーライドして、コールをターゲットに委任します。したがって、前の例でメソッドがfinal
だった場合は、this.someField
にアクセスするとNullPointerException
になります。
これはすべて、プロキシの代わりにバイトコード計測を使用するようにHibernateを設定することで回避できますが、それは独自の落とし穴を持ち、広く採用されていません。
2)再び、プロキシインスタンス自体は初期化されません。ターゲットインスタンスの初期化では、フィールドまたはプロパティのアクセスがマッピングで定義されているかどうかによって異なります。どちらの場合も、リフレクションが使用されます(フィールドアクセスの場合はフィールドに直接値を割り当て、プロパティアクセスの場合はセッターを呼び出す)。