コンポーネントMixin

Tapestry 5 は革新的な特徴を備えています。コンポーネントMixin です。コンポーネントMixinは巧妙なコンセプトです; Mixinと呼ばれる特別なコンポーネントを正統なコンポーネントに混ぜ合わせることができます。 コンポーネントとそのMixinはコンポーネントテンプレート内でひとつのタグとして表されますが、コンポーネントとMixinのすべての振る舞いを持っています。

入力フィールドに検証を追加したり、Ajaxの効果や動作を全てのコンポーネントに追加するためにMixinは設計されました。

Mixinはコンポーネントのマッシュアップと考えることができます; Mixinの振る舞いをコンポーネントの振る舞いに結合させ、一カ所に束ねるのです。

Mixinはふたつの異なるシナリオで用いられます: インスタンスMixin実装Mixin です。

Mixinクラス

Mixinクラスは、コンポーネントやページクラスのサブパッケージと同様に、 アプリケーション(またはライブラリの)ルートパッケージ下の mixins サブパッケージに配置します。

パッケージが異なること以外、Mixinクラスはコンポーネントクラスとまったく同じです。

Mixinの制限

今のところ、コンポーネントにできることなら、パラメータやレンダーフェーズメソッドも含めてすべてMixinにもすることができます。

Mixinはテンプレートを持つことができません。 レンダーフェーズメソッドの実行という点では、Mixinはコンポーネントに完全に統合されています。

Mixinは永続フィールドを持つことができますが、今のところこれは完璧には実装されていません (Mixinとコンポーネントの間で、あるいは他のMixinとの間で名前の衝突が起こる可能性があります)。 Mixinで永続フィールドを使用する場合は十分に注意してください ... もっと良いのは永続値の保存はパラメータ経由でコンテナに委譲することです。

Mixin自身がMixinを持つことはできません。

インスタンスMixin

インスタンスMixinとは、コンポーネントのある特定の インスタンス に対してMixinを適用することです。 これはコンポーネントテンプレート内で<comp>要素のmixinsアトリビュートを用いて行います。 mixinsアトリビュートにはMixin名のカンマ区切りリストを与えます。

Componentアノテーション を用いてコンポーネントの型を定義する際にMixinを適用することもできます。その場合は次のふたつの方法があります:

ひとつ目の方法は記述量が少なくて済みます。また、コアMixinをアプリケーション独自のMixinで置き換えることができます。 ふたつ目の方法はより具体的で、またリファクタリングしやすいです (Mixinクラスの名前を変更すると、MixinClassesアノテーション内に書かれたクラス名も変更されるでしょう)。

例:

  @Component(parameters=. . .) @Mixins({"Autocomplete", "DefaultFromCookie"})
  private TextField userId;

この例ではTextField型のコンポーネントと、AutocompleteおよびDefaultFromCookieという 仮想の Mixinを定義しています。

実装Mixin

実装Mixinはあるコンポーネントのインスタンス全てに適用されるMixinです。 実装Mixinには Mixinアノテーション を使用します。 このアノテーションはMixinインスタンスを参照するフィールドを定義します。

public class AutocompleteField extendes TextField
{
  @Mixin
  private Autocomplete autocompleteMixin;
  
  . . .
}

多くの場合、インスタンス化するMixinの具象クラスをフィールドの型とします。

しかし、インターフェースや基底クラスをフィールドの型とする場合は、アノテーションのvalueアトリビュートを用いてMixinクラス名を指定することができます:

public class AutocompleteField extendes TextField
{
  @Mixin("Autocomplete")
  private Object autocompleteMixin;
  
  . . .
}

Mixinパラメータ

Mixinはコンポーネントと全く同じようにパラメータを持つことができます。

(テンプレート内であっても、Componentアノテーションのparametersアトリビュートを使う場合でも)パラメータをバインドする際に、 Tapestryは(コンポーネントとMixinの)各クラスで定義されているパラメータから各パラメータ名に対応するものを見つけます。

コンポーネントとMixinがどちらも同じ名前のパラメータを定義している場合、コンポーネントが勝ちます: コンポーネントのパラメータがバインドされMixinのパラメータはバインドされません。

しかし、パラメータ名の前にMixinクラスの 非限定 名を付けることで、曖昧さを排除することができます。例:

  @Component(parameters={"Autocomplete.id=auto", . . . }) @Mixins("Autocomplete", "DefaultFromCookie"})
  private TextField userId;

レンダーフェーズの順序

ひとつのコンポーネントに統合された全てのMixinは、ほとんどのフェーズでそのコンポーネントよりも 前に レンダーフェーズメソッドを実行します。 しかし、終盤のフェーズ(AfterRender, CleanupRender)では実行順序は逆になります。

例外: MixinAfter でアノテーションされたMixinはコンポーネントの前ではなく 後に 実行されます。