前回は「JSR 299: Web Beans」についてEarly Draftを元にその概要を紹介した。今回は同仕様の肝であるWeb Beanコンポーネントを構成する各要素について細かく見ていこうと思う。ソースコード例はEarly Draftより部分的に引用している。

コンポーネントタイプ

コンポーネントタイプは、コンテナがそのWeb Beanコンポーネントの実装クラスを特定するために使用される。また、コンポーネントの優先度を決定するためにも使われる。コンポーネントタイプはアノテーションによって宣言することができ、JSR 299には@Componentと@Standardという2種類のタイプがあらかじめ用意されている。Web Beansコンテナによって提供されるコンポーネントはすべて@Standardであり、アプリケーションで宣言するコンポーネントにはリスト1のように@Componentを指定する。

リスト1 コンポーネントタイプの使用例

@Component
public class MyComponent { ... }

オリジナルのコンポーネントタイプを定義することもできる。その場合、@ComponentType、@Target、@Retentionなどのアノテーションを使ってリスト2のように宣言する。

リスト2 コンポーネントタイプの定義

@ComponentType
@Target({TYPE, METHOD})
@Retention(RUNTIME)
public @interface MyComponentType {}

実装クラスとプロデューサメソッド

Web Beanの実装クラスは、Web Beanコンポーネントの状態や振る舞いを決定する。Web Beanコンポーネントのプロデューサメソッドは、インジェクトされるオブジェクトのソースとして振る舞うメソッドを指す。プロデューサ・メソッドは@Producesアノテーションを用いてリスト3のように定義する。@AllProductsはバインディングアノテーション(後述)である。

リスト3 プロデューサメソッドの定義

@Component
@Stateless
public class ShopBean implements Shop {
       @Produces @AllProducts
       public List getAllProducts() { ... }
}

プロデューサメソッドはリスト4のようにインジェクトできる。

リスト4 プロデューサメソッドコンポーネントのインジェクト

@In @AllProducts List catalog;

APIタイプ

Web BeanのAPIタイプとは、クライアントから見たWeb Beanコンポーネントの型を指す。Web Beanコンポーネントは複数のAPIタイプを持つことができる。各Web BeanコンポーネントのAPIタイプは以下のようにして決まる。

  • 実装クラスがセッションBeanでない場合、その実装クラスおよびスーパークラス、実装インタフェースがすべてAPIタイプとなる
  • 実装クラスがセッションBeanの場合、すべてのローカルインタフェースとそのスーパーインタフェースがAPIタイプになるが、リモートインタフェースは含まれない
  • プロデューサメソッドコンポーネントの場合、メソッドの戻り値の型とすべての実装インタフェースがAPIタイプとなる。戻り値の型がコンクリートクラスの場合、そのスーパークラスもAPIタイプに含まれる

バインディングアノテーション

バインディングアノテーションは、必要とするWeb Beanコンポーネントを特定するために独自に定義するアノテーションである。@BindingTypeアノテーションを用いてリスト5のように定義する。

リスト5 バインディングアノテーションの定義

@BindingType
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD})
public @interface AllProducts {}

定義したバインディングアノテーションは、Web Beanの実装クラスやプロデューサメソッドに指定することができる。そしてそれらのWeb Beanコンポーネントをインジェクトする際には、バインディングアノテーションによってソースとなるオブジェクトが特定される(リスト3はリスト4参照)。したがって、同じAPIタイプでもバインディングアノテーションが異なればソースのオブジェクトも異なる。

スコープ

すべてのWeb Beanコンポーネントはスコープを持っており、それによってライフサイクルと他のコンポーネントからの可視性が決まる。Web BeansではServlet仕様で定義される各スコープ、すなわちリクエストスコープ、アプリケーションスコープ、セッションスコープに対応した@RequestScoped、@ApplicationScoped、@SessionScopedというアノテーションが用意されており、これをWeb Beanコンポーネントに指定すればよい。その他に対話型のコンテキストに対応した@ConversationScopedがある。

また、@ScopeTypeアノテーションによって独自のスコープを定義することもできる。リスト6のようにする。

リスト6 スコープの定義

@ScopeType
@Target({TYPE, METHOD})
@Retention(RUNTIME)
public @interface MethodScoped {}

コンポーネント名

通常、Web Beanコンポーネントはコンポーネント名を持つ。これはUnified EL式の中でコンポーネントを特定するために使用される。デフォルトではコンポーネントの実装クラス名がそのままコンポーネント名となる。プロデューサメソッドの場合はメソッド名か、またはメソッド名がJavaBeansプロパティのGetter形式ならばそのプロパティ名がコンポーネント名となる。たとえばメソッド名が「getProducts」ならばコンポーネント名は「products」だ。

デフォルト以外のコンポーネント名を付けたい場合には、リスト7のように@Namedアノテーションで指定すればよい。

リスト7 コンポーネント名の指定

@Component
@Named("products")
public class ProductList implements DataModel { ... }

Web Beans仕様にはもうひとつ、pseudo-scopeと呼ばれるスコープがある。通常、2つのコンポーネントX、YがそれぞれコンポーネントZをインジェクトしていた場合、それぞれのインスタンスx、yは同じZのインスタンスへの参照を保持する。しかしpseudo-scopeを持つコンポーネントは、複数のコンポーネントでインスタンスが共有されない。そしてpseudo-scopeのコンポーネントのライフサイクルは、インジェクトされた各コンポーネントのライフサイクルに依存することになる。poseudo-scopeの指定には@Dependentアノテーションを利用する。

今回紹介したソースコードはすべてアノテーションを用いた例だが、JSR 299では同様の定義をXMLを用いて記述する方法も定められている。詳細はEarly Draftを参照していただきたい。JSR 299は2008年4月に正式リリースされる予定となっていたが、現在のところスケジュールは遅れ気味のようだ。いずれにせよJava EE 6のリリース (2008年第四半期に予定) までには正式仕様が決まるはず。Java EE 6を導入する予定のあるユーザは早い段階でチェックしておくといいだろう。