コンポーネントへのインジェクション

インジェクション はTapestryのキーコンセプトのひとつです。Tapestry IoC コンテナ はサービスビルダメソッドへのパラメータにインジェクションを利用しています。

コンポーネントへのインジェクションには全く別の方針を取っています: インスタンス変数へ直接インジェクションします。

Injectアノテーション

Inject アノテーションを使用し、サービスやその他のリソースをインジェクトするフィールドを指定します。

Tapestryには2種類のインジェクションがあります:

  • 個々のサービスを指定しインジェクトする、明示的インジェクション。
  • フィールドの型によってインジェクトするオブジェクトが決まる、デフォルトインジェクション。

どちらの場合もフィールドはリードオンリーに変換されます。 この変換は実行時に行われます(これは、コンポーネントがテスト可能であるという点において非常に重要なことです)。 インジェクトされたフィールドを変更しようとすると実行時例外が発生します。

またいくつかの特別なケースとして、フィールドがある特定の型である場合や、 Injectアノテーションの他に追加のアノテーションがフィールドに与えられている場合があります。

Assetインジェクション

Pathアノテーションも与えられている場合、 インジェクトされる値は(コンポーネントからの相対パス上にある)ローカライズされたアセットです。

アノテーションの値の中にあるシンボルは展開されます。

Blockインジェクション

Block型のフィールドは、コンポーネントテンプレート内の<block> 要素がインジェクトされます。 通常はフィールド名と同じidを持つblock要素がインジェクトされます(フィールド名の先頭に "_" か "$" がある場合は取り除かれます)。 これが適切でない場合、Idアノテーションを使う事ができます:

  @Inject
  private Block foo;
  
  @Inject
  @Id("bar")
  private Block barBlock;

ひとつ目のインジェクションでは、idが "foo" のblock要素がインジェクトされます(いつものように、idの大文字小文字は区別されません)。 ふたつ目のインジェクションでは、idが "bar" のblock要素がインジェクトされます。

Resourceインジェクション

ある数種類の型のフィールドには、コンポーネントに関連する リソース がインジェクトされます。例えば、コンポーネントのロケールがそうです。

コンポーネントがそれ自身のリソースにアクセスする必要が生じるとき、 というのはリソースインジェクションのとても一般的な例です。 コンポーネントに適切な型のフィールドを定義し、そのフィールドにInjectアノテーション与えます:

@Inject
private ComponentResources resources;

Tapestryは、このフィールドに何をインジェクトしたらよいかをフィールドの型によって判断します。ここではComponentResources型です。

以下の型がリソースインジェクションをサポートしています:

java.lang.String
コンポーネントの完全なIDです。コンポーネントの完全なIDとは、ページの完全修飾クラス名とコンポーネントのIDを連結したものです。
java.util.Locale
コンポーネントのロケールです(同じページ内のコンポーネントはすべて同じロケールを使用します)。
org.slf4j.Logger
コンポーネント用に設定されたLoggerのインスタンス。設定はコンポーネントのクラス名によって行います。 SLF4J はLog4Jまたは他のロギングツールキットのラッパーです。
org.apache.tapestry5.ComponentResources
コンポーネントのリソースです。しばしばコンポーネントに関連したリンクを生成するのに使用します。
org.apache.tapestry5.ioc.Messages
コンポーネントのメッセージカタログです。ローカライズされたメッセージを生成することができます。

明示的なサービスインジェクション

ある特定のオブジェクトを要求するには、 Serviceアノテーションを用いてサービス名を指定します。

例:

@Inject
@Service("Request")
private Request request;

通常これは必要ありません; インジェクトするサービスの特定は常に、明示的なIDの指定によるものでなく単に型によってできるべきです。 明示的なIDはリファクタリング時に安全ではないという欠点があります: もしサービスインターフェースの名前を変更しサービスIDもそれに合わせて変更したなら、 (そのような変更はRequestサービスにおいては起こることは無いはずです。しかし、あなた自身が作成した独自のサービスでは...) 明示的なサービスIDの指定による既存のインジェクションは壊れてしまうでしょう。

デフォルトインジェクション

インジェクトするサービスやオブジェクトを特定するのにフィールドの型やその他のアノテーションだけでは不十分な場合、Tapestryは残りの2つの方法を実行します。 その場合、サービスのインターフェースによってサービスを特定するためにフィールドの型を用います。

ひとつ目は、Aliasサービスによって生成されるオブジェクトプロバイダを調べます。 オブジェクトプロバイダは、複数のサービスが同じサービスインターフェースを実装しているときの曖昧さをなくすために使用します。

ふたつ目は、フィールドのインターフェースを実装している唯一のサービスを探します。 これは、そのインターフェースを実装しているサービスがひとつも無い場合や、複数のサービスが実装している場合には失敗します。 後者の場合、Aliasサービスをcontributionするか、@Serviceアノテーションでサービスを明示的に指定して、曖昧さを回避しなければなりません。

新しいインジェクションロジックの定義

匿名インジェクションはInjectionProviderサービスによって制御されています。 このサービスはchain of commandによってコンポーネントへのインジェクションを扱っています。