Eclipse 4 (e4) Tutorial Part 6: Behavior Annotations
この連載シリーズの以前のパートでは、アプリケーションモデルの作り、それを実装にリンクする方法、アプリケーションモデルを拡張する方法を説明しました。このチュートリアルの最後のパートでは、依存性注入の詳細を説明します。
ある場所でどのパラメータが注入されるかについて影響を与える方法にフォーカスします。多くの場合では、正確にいつパラメータが注入されるか、さらに精密に、あるクラスのあるメソッドがフレームワークによっていつ呼び出されるかを仕様化することも重要になります。
Eclipse 4は、この目的にアノテーションを使用します。このチュートリアルでは、Eclispe 4で使われる最も重要なアノテーションを説明します。
注入タイミング?
このチュートリアルの以前のパートで説明した、@Named and @Optionalと組み合わせた @Injectアノテーションを使うと、コンストラクタとフィールドへの依存性注入は、十分制御できます。どちらの場合でも、オブジェクトが注入される時点は明確(クラスがインスタンス化されるとき)です。メソッドが@Injectのみでマークアップされている時、これらのメソッドは、クラスが初期化された後に一度呼ばれ、以降、コンテキスト内でパラメータが変化する度に呼ばれます。
しかし、開発者がある種のイベント、例えば、ビューがフォーカスを得た場合や、オブジェクトが削除されたときなどに反応したいと考えるような多数のユースケースがあります。
Eclipse 3.xのインタフェースでは、これらのイベント向けのメソッドを定義していました。
例えばsetFocus()は、あるイベントがトリガされたときにフレームワークによってよばれます。
Eclipse 4では、ビューはPOJOであり、任意の名前を付けることが可能です。そのため、ある時点でフレームワークに呼ばれる必要があるメソッドは、例えば、@Focusなど、対応するアノテーションでマークアップしなければなりません。すべてのここで説明されるアノテーションは、@Injectと同様に依存性注入の振る舞いを含みます。
つまり、もし、以下で説明するアノテーションでメソッドがマークアップされていれば、そのメソッドのすべてのパラメータは、@Injectを明示的に付けなくても注入が行われるでしょう。
@PostConstruct と @PreDestroy
多くのケースでは、オブジェクトは、コンストラクタが呼ばれた後に追加の初期化処理を必要とします。これは、フィールドを使用している場合に特にあてはまります。フィールドは、コンストラクタが呼ばれた後に注入されるので、フィールドに依存する初期化は、コンストラクタ内では行うことができません。
オブジェクトを初期化する典型的なタスクは、リスナの登録です。リスナは、オブジェクトがそれ以上必要なくなったときに登録解除される必要があります。
このユースケースに対して、Eclipse 3.xのインタフェースは、たいていinit()やdispose()のようなメソッドを用意しています。
Eclipse 4では、 javax.annotationで定義されている@PostConstruct と @PreDestroyなる2つの標準的なアノテーションを使います。
@PostConstructでアノテートされたメソッドは、クラスがそのコンストラクタで初期化された後、もしくはすべてのフィールドが注入された後に呼ばれます。
@PreDestroyでアノテートされたメソッドは、オブジェクトが必要とされなくなった時、例えば、対応するビューがクローズされ、そのオブジェクトが削除される前に呼ばれます。
以前に触れたように、すべてのアノテーションは、これらのメソッドで追加のパラメータを使うことができ、義務的に並べる必要はありません。
次のコードは典型的な使用例を示します。サービスは、フィールドとして注入され、それゆえ、コンストラクタで使用することはできません。@PostConstruct メソッドは、そのサービス上でリスナ登録するのに使われ、@PreDestroyメソッドは、リスナ登録を解除するのに使われます。
|
@PostConstruct と @PreDestroyはすべてのクラス向けに利用でき、フレームワークまたは注入ファクトリを手動で使うことによって初期化されます。
@Focus
パーツなどのビジュアル要素に対しては、実装が反応すべき追加的なイベントがあります。@Focusアノテーションでマークアップされたメソッドは、対応するUI要素がフォーカスを取得したときに呼ばれます。
SWTアプリケーションでは、フォーカスは中心的なSWT要素、例えばテキストフィールドやツリーUIに送られるはずです。ビュー実装が複数のSWTコントロールを含んでいるとき、開発者はコントロールを選択する必要があります。フォームエディタであれば、たいていは最初のテキストフィールドになります。
|
@Persist
@Persistアノテーションは、パーツ上で保存がトリガされたときに呼ばれるメソッドにマークアップします。
たとえば、そのパーツがテキストエディタに相当する場合、テキストコントロールの内容はファイルに保存されます。
|
このメソッドは、例えば、ハンドラなど、たいてい他の場所から呼ばれます。パーツサービスは、特定のパーツもしくはダーティ状態のすべてのパーツを保存するためのヘルパメソッドを提供します。
|
@PersistState
@PersistStateでマークアップされたメソッドは、オブジェクトが廃棄される前で、かつ、@PreDestroyでマークアップされたメソッド呼び出しの前に、呼ばれます。このメソッドの目的は、必要に応じて要素の最新の状態を保持することです。
もしそのメソッドがビューであれば、最新のユーザ入力が利便性のために保存されるといったことが可能になるでしょう。
@Execute と @CanExecute
特にハンドラに向けた @Execute と @CanExecuteといった追加的な2つのアノテーションがあります。@Executeは、ハンドラ自身が実行される場合に実行されるメソッドをマークアップします。@CanExecuteは、ハンドラの実行可能状態を管理するメソッドをマークアップします。
そのため、@CanExecuteが与えられたメソッドは、ブール値を返す必要があり、フレームワークに対して、実装されたアクションが現在使用できるか否かを知らせます。結果として、Eclipse 4は、すべてのメニューとツールバー項目をこのハンドラにリンクする形でイネーブル、ディスエーブルに設定します。すべてのアノテーションに関して、すべての要求されたパラメータは、注入されます。
しかし、@CanExecuteアノテーションは、他のアノテーションとはとても異なる動作をします。 このアノテーションは、ある種のイベントやコンテキスト内の何らかのパラメータ変更に基づいて呼ばれません。実際に、バージョン4.2では、継続的にタイマーベースで呼ばれます。なので、このメソッド内で多くの時間を費やすことを避けることは重要です。
@CanExecute メソッドのありふれた実装例は、現在の選択、アクティブなパーツ、アクティブなパースペクティブに対するチェックです。
次の例では、現在の選択対象が、特定の型を持ち、もしそうならハンドラを有効にするといったチェックを行います。@Executeメソッドは、現在の選択についてあるアクションを実行します。
|
ライフサイクルアノテーション
最後の説明となりますが、Eclipse 4は、アプリケーションの実行ライフサイクルをフックする機能を提供します。これを行うためには、ライフサイクルハンドラが登録されたアプリケーションのプロパティとして登録される必要があります。
|
ライフサイクルハンドラ自身の実装は、POJOです。
アプリケーションコンテキストが生成された後に呼ばれます。コンテキストにオブジェクトを追加したり、削除したりするのに使うことができます。
@ProcessAdditions と @ProcessRemovals
スクリーン上にアプリケーションを表示するためのレンダラに渡される前に、アプリケーションモデルの変更を可能にします。アプリケーションが実際に表示される前にアプリケーションモデルの要素を追加したり、削除することが可能になります。
アプリケーションモデルが保存される前に呼ばれます。保存前にモデルを変更することが可能になります。
まとめ
Eclipse 4の振る舞いについてのアノテーションは、オブジェクトの精密な注入時点を定めることができます。アノテートされたメソッドは、パラメータを要求することができます。
しかし、必要無ければそうする必要はありません。
例えば、@Focusでアノテートされたメソッドは、しばしばパラメータを必要としません。このケースにおいては、フォーカスメソッドが、対応するUI要素がフォーカスを取得したタイミングで呼ばれることの方が重要となります。
@Inject, @Named, @PostConstruct, @PreDestroyのようなアノテーションはJava標準です。@Optional, @Persistのような追加的なアノテーションは、Eclipse 4特有のものです。
利用できるアノテーションのソースの概要を得るために、これまでに説明したすべてのアノテーション と、それを定義しているバンドルを以下のリストを示します。もし、これらのアノテーションのいくつかを利用する場合、依存設定やパッケージのインポートが必要になります。
@Active | org.eclipse.e4.core.contexts |
@Creatable | org.eclipse.e4.core.di.annotations |
@CanExecute | org.eclipse.e4.core.di.annotations |
@Execute | org.eclipse.e4.core.di.annotations |
@Inject | javax.inject |
@Named | javax.inject |
@Optional | org.eclipse.e4.core.di.annotations |
@Persist | org.eclipse.e4.ui.di |
@PersistState | org.eclipse.e4.ui.di |
@PostConstruct | javax.annotation |
@ProcessAdditions | org.eclipse.e4.ui.workbench.lifecycle |
@ProcessRemovals | org.eclipse.e4.ui.workbench.lifecycle |
@PostContextCreate | org.eclipse.e4.ui.workbench.lifecycle |
@PreDestroy | javax.annotation |
@PreSave | org.eclipse.e4.ui.workbench.lifecycle |
完結!