例で説明します。 エンティティがあるとしましょう:
@Entity public class Person { @Id private long id; private String firstName; private String lastName; @OneToMany private List<Person> children; // getters-setters }
このエンティティの表現がクライアントに送信されたときに、子リストが初期化され、さらにHibernateガーターをプルしないようにする必要があります。 これを行うには、次のインターフェイスを宣言します。
public interface IPerson { public long getId(); public void setId(long id); // getters-setters for firstName/lastName public List<IPerson> getChildren(); public void setChildren(List<IPerson> children); }
クライアントに送信されるのはこのビューです。 PersonはIPersonを実装しないことに注意してください。 また、クライアントはPersonの存在についてまったく知りません。 彼にとって、インターフェースという形での彼のさまざまな表現しかありません。 プロキシは次のようになります。
Person examplePerson = getPersonFromDb(); IPerson personProxy = ProxyFactory.getProxy(IPerson.class, examplePerson);
どのように機能しますか? ProxyFactory.getProxy()メソッドは、動的プロキシメカニズムを使用して、IPersonインターフェイスの実装を作成します。このハンドラーには、フィールド値を持つMapがあります。 このマップを埋めるために、ProxyFactoryはエンティティフィールドexamplePersonのリフレクションを読み取ります。 したがって、インターフェイスでゲッター/セッターが呼び出されると、ハンドラーはこのマップに忍び込みます。
当然、エンティティには複数のインターフェイスを含めることができ、プロキシにはフィールドの一部のみを含めることができます。 リストの例(リスト<IPerson>の例)の場合、リストを構成するプロキシを指定することもできます(たとえば、リスト<IPersonOnlyWithName>)。
コンパイル段階でプロキシインターフェイス(インターフェイスが実際にエンティティに対応していること)をチェックするために、次のように注釈が付けられたエンティティを通過する単純なAntビルダーがEclipse用に作成されました。
@Entity @ProxyBinding(interfaceClass = IPerson.class) public class Person { // … }
このアプローチは、実際にその実行可能性を証明し、さまざまな追加を獲得しました。 建設的な批判やコメントを見るのは面白いでしょう。