InterType サポート
リリース前だというのにやたらと (苦笑) 話題になっているらしいので一応説明を書いておくテスト.
S2 の次のリリースでは InterType という機能がサポートされます.
これは AspectJ の Inter-type Declarations (インタータイプ宣言) にインスパイヤ (笑) されたもので,従来の MethodInterceptor
による「動的な振る舞いの変更」に加えて,「静的な構造の変更」を実現します.
「動的な振る舞いの変更」「静的な構造の変更」は千葉先生の「アスペクト指向入門 (isbn:4774125814)」からのインスパイヤね.
ちなみに Google で「inter type」を検索すると,「もしかして: intertype」と表示されます.
AspectJ では "Inter-type" だけど,"intertype" も普通に単語としてあるらしい.
ALC の英辞郎で調べてみると,
intertype
【名】インタータイプ
って,カタカナにしただけやんけ!!
つまり,日本語としても普通の単語ということです.マジですか?
「静的な構造の変更」というのは,次のようなものを含みます.
AspectJ では他に例外のソフト化などもありますが,S2 ではサポートしていない (できない) ので省略.
Inter-type Declarations は,複数のタイプ (クラスやインタフェース) 間にまたがってこれらを宣言するわけですね.
なので,Inter-type Declarations.
S2 では org.seasar.framework.aop.InterType
インタフェースを実装したクラスにより,Inter-type Declarations を実現します.
AOP Alliance では同様の機能のために org.aopalliance.instrument
パッケージを規定しているようなのですが,これと Javassit との間を取り持つのがとてもとてもとても大変そうだったので,採用を見送って独自のインタフェースを用意しました.心より恥じる.
なので,InterType
は S2 と Javassist に依存しまくりになります.
InterType
実装クラスは,Javassist を使ったバイトコード操作によって対象クラスのサブクラスにフィールドやメソッドの追加を行います.
このバイトコード操作は最初にインスタンスが必要とされた時点で一回のみ行われます.singleton ではコンテナの初期化時です.
生成されたバイトコードは通常のクラスとしてクラスローダーにロードされるため,その後のインスタンス生成やメソッド呼び出しにオーバーヘッドは一切ありません.
これは現在の MethodInterceptor
の編み込みと同じです.
内部的には,サブクラスを生成して,(もしあれば) MethodInterceptor
を呼び出すためのメソッドをサブクラスに追加 (オーバーライド) した後に (もしあれば) InterType
を呼び出し,できあがったバイトコードをクラスとしてロードします.
InterType
を利用するには,dicon では <component>
要素の子として <interType>
要素を指定します.
要素の内容は InterType
を実装したコンポーネント.
<component class="..."> <interType>aop.propertyInterType</interType> </component>
あるいは,@InterType
アノテーションを使うこともできます.
Tiger と Backport175,それに定数アノテーションが利用可能です.
標準の InterType として,org.seasar.framework.aop.intertype.PropertyInterType
が提供されます.
というか,これを提供するために InterType のサポートが追加されたわけですが.
これを作ってくれたのは,「なぜ、あなたはJavaでオブジェクト指向開発ができないのか (isbn:477412222X)」の著者で,Javassist チュートリアルの翻訳もしてくださった,こもりさん.
これを機に S2 コミッタの一員に加わって頂きました.S2JMS のコミッタでもあります.
PropertyInterType
は,@Property
アノテーションが付けられたフィールドに対して getter/setter メソッドを追加する InterType です.
例えば
@InterType("aop.propertyInterType") public class Hoge { @Property String foo; }
なんてクラスを S2 コンテナに登録 (dicon でも自動登録でも) すると,
-
public String getFoo() { return foo; }
public void setFoo(String foo) { this.foo = foo; }
という二つのメソッドを追加したサブクラスが作成されます.
このため,フィールドは非 private
でなければなりません.
@Property
アノテーションには PropertyType
を指定することもできて,
@InterType("aop.propertyInterType") public class Hoge { @Property(PropertyType.READ) String foo; }
とすると getter のみ作成され,setter は作成されません.
PropertyType.WRITE
を指定すると setter のみ作成されます.
デフォルトは PropertyType.READWRITE
です.
クラスに対して @Property
アノテーションを指定すると,その値がアノテーションの付けられていないフィールドに適用されます.
@InterType("aop.propertyInterType") @Property public class Hoge { String foo; Object bar; @Property(PropertyType.NONE) int baz; }
なんて書くと,foo
と bar
には setter と getter が作成されますが,baz
には何も作成されません.
なお,PropertyInterType
の @Property
アノテーションは,Tiger アノテーションと Backport175 アノテーションのみサポートし,定数アノテーションはサポートしません.
PropertyInterType
は,主に S2JSF での DTO,Struts では ActionForm
と呼ばれるような類のクラスに適用することを想定しています.
Goya ではプレゼンテーションモデルと呼ばれるものです.
これらのクラスは,S2JSF や S2Struts などのプレゼンテーションフレームワークと,背後のドメイン層とかビジネスロジック層などと呼ばれるレイヤとの間のインタフェースとして使われます.
こんな感じ.
S2JSF などのフレームワークは DTO のプロパティに直接アクセスするわけではなく,HTML や JSP などに記述された式言語を元にリフレクションを通じて DTO のプロパティにアクセスします.
そしてドメイン層の側はというと,受け取った DTO をドメイン側のモデル (ドメインモデル) に変換します.
おっと,プレゼンテーションモデルとドメインモデルは分離する派と分離しない派があるようですが,分離しない派はここではお呼びでないということで.
んで,モデル間の変換をする際には,2 月中旬にリリース予定という S2Dxo を使うとか,今なら BeanUtil を使うとかできるわけですが,いずれにしてもリフレクションを通じてのアクセスになります.
つまり,DTO のプロパティを直接触る人 (コード) は存在しないということに.
いくら IDE のサポートがあるとはいえ,そんな DTO のためにいちいち getter/setter なんて書いてられるかぁ〜って場合に PropertyInterType
をお使いください.
なお,InterType の説明を含むドキュメントが一部 s2container.seasar.org 上で公開されてしまっていますが,手違いです (苦笑).
なんたってまだリリース前なので...
リリースの時期は,ひがさんのプロダクト計画によると「1月の早いうち」らしいので,遅くても来週末かな?
世間的には InterType より EJB3 (SLSB, SFSB) のサポートが目玉でしょうけど.