PartialBeanによるタイプセーフなハンドラー実装

DeltaSpike PartialBeanモジュールはインタフェース(または、抽象クラス)とハンドラーをバインドする仕組みを提供します。PartialBeanを使うとBeanの実装クラスを(Reflectionでお馴染みの)InvocationHandlerとして実装することができます。Partial(部分的な、不完全な)というのは、インタフェースを実装すればハンドラーが実装を提供するので、開発者がBeanの完全な実装をしなくとも良いという意味でしょう。

InvocationHandlerというと、それを聞いた人はきっとJavaのDynamic Proxyを想像されると思います。Dynamic ProxyではProxyへの呼び出しはターゲットのオブジェクトを呼び出します。しかし、このPartialBeanは実装上の仕組みとしてはDynamic Proxyを使ってはいるものの、ターゲットのBeanが別に存在するのではなく、ハンドラー自身がCDI Beanとして扱われます。ここが重要です。PartialBeanはCDIのインタセプターとは異なり、Beanの呼び出しに割り込んで何かを処理するものではなく、Beanそのものとしてインジェクションの対象になるのです。

そこで、PartialBeanではインタフェース部分の定義が重要になります。PartialBeanでは、インタフェースにおけるメソッド定義やメソッドに付加されたアノテーションの情報に基づいてハンドラーが処理を実行します。例えば、DeltaSpike DataモジュールではQueryの定義の実装にPartialBeanを使用しています。クエリの式をメソッドのアノテーションとして提供するのです。

@Query("select p from Person p where p.ssn = ?1")
Person findBySSN(String ssn);

これが意味することをよく考えてみましょう。ハンドラーはアノテーションの情報を使ってクエリを実行することができます。開発者はインタフェースからSQL式を理解することができ、しかもクエリを実行するときはメソッドを実行すれば良いのです。メソッドは引数の型や戻り値の型を提供しますから、呼び出し側が間違った呼び出しをしてもコンパイル時に型の不整合を検出することができます。つまり、タイプセーフです。PartialBeanは文字列の世界とタイプセーフな世界をつなぐ面白い仕組みと言えるでしょう。

PartialBeanのセットアップ

PartialBeanモジュールを使うにはMaven pom.xmlの依存ライブラリとして以下の設定を追加します。

		<dependency>
		    <groupId>org.apache.deltaspike.modules</groupId>
		    <artifactId>deltaspike-partial-bean-module-api</artifactId>
		    <version>${deltaspike.version}</version>
		    <scope>compile</scope>
		</dependency>
		
		<dependency>
		    <groupId>org.apache.deltaspike.modules</groupId>
		    <artifactId>deltaspike-partial-bean-module-impl</artifactId>
		    <version>${deltaspike.version}</version>
		    <scope>runtime</scope>
		</dependency>

@PartialBeanBindingの定義

インタフェースとハンドラーを結びつけるためには@PartialBeanBinding使って定義されたアノテーションが必要です。この例では@MyPartialBeanBindingというアノテーションを定義しています。

package org.tanoseam.examples;

import org.apache.deltaspike.partialbean.api.PartialBeanBinding;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;

@PartialBeanBinding
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyPartialBeanBinding {}

インタフェース実装の例

次はPartialBeanのインタフェースの例です。@MyPartialBeanBindingというアノテーションをつけているので、これがPartialBeanであることがわかります。また、メソッド定義に@ValueHolderというアノテーションが付いているのに注意してください。このアノテーションは、後で、ハンドラー実装で参照します。

package org.tanoseam.examples;

import javax.enterprise.context.Dependent;

@Dependent
@MyPartialBeanBinding
public interface MyPartialBean {
    @ValueHolder(value="PartialBean")
    String getValue();
}

ハンドラーの実装

PartialBeanのハンドラーはInvocationHandlerのInvokeメソッドを実装します。
このサンプルプログラムでは、メソッドに付加されたアノテーションからvalueを取得しています。

package org.tanoseam.examples;

import java.lang.reflect.Method;
import javax.enterprise.context.Dependent;

@Dependent
@MyPartialBeanBinding
public class MyPartialBeanHandler implements java.lang.reflect.InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        ValueHolder holder = method.getAnnotation(ValueHolder.class);
        String value = holder.value();
        return value;
    }
}

テストコード

PartialBeanの使用方法は簡単で、通常のBeanと同様に@Injectで変数に設定することができます。

package org.tanoseam.examples;

import static org.junit.Assert.assertEquals;

import org.apache.deltaspike.testcontrol.api.junit.CdiTestRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
import javax.inject.Inject;

@RunWith(CdiTestRunner.class)
public class PartialBeanTest {

    @Inject
    private MyPartialBean bean;

    @Test
    public void testPartialBean() {
          assertEquals("PartialBean", bean.getValue());
    }
}
広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。