GIN (GWT INjection)を使ってみる

GIN(GWT INjection)は、GoogleのDIフレームワークであるGuiceGWT版で、GWTのクライアントサイドで使用するためのものです。現在リリースされているバージョンはGuice2.0ベースです。
モジュールの定義方法はGuiceと同じですが、GWTゆえの制約があります。GWTではクライアントコードではリフレクションは利用できないため、コンパイル時点での情報しか利用できません。そのためGuiceの一部の機能が使えなかったり、多少冗長なコードが必要になります。

GINを使う準備

GINのサイトからzipファイルをダウンロードして、

  • gin-1.0.jar
  • guice-2.0.jar
  • aopalliance.jar

をビルドパスに追加します。

.gwt.xmlファイルに以下の記述を追加します。

<inherits name="com.google.gwt.inject.Inject"/>

以上で準備は完了です。

GinModuleでモジュールを定義する

ここでは、Contactsアプリケーションで、Activityに必要なオブジェクト(View, RPCサービス, PlaceController)をインジェクトする例を使います。Activityには以下のようにコンストラクタインジェクションを行うために@Injectアノテーションを付加します。コンストラクタインジェクション以外に、メソッドインジェクション、フィールドインジェクションなども使用可能です。

public class ContactsActivity{
	private ContactsView view;
	private PlaceController placeController;

	@Inject
	public ContactsActivity(ContactsServiceAsync rpcService, ContactsView view,
			PlaceController placeController) {
		this.rpcService = rpcService;
		this.view = view;
		this.placeController = placeController;
	}
}

モジュールの定義は、GinModuleインタフェースを実装したクラスに記述します。以下の例ではAbstractGinModuleを継承して使用しています。

public class ContactsModule extends AbstractGinModule {
	@Override
	protected void configure() {
		bind(ContactsView.class).to(ContactsViewImpl.class).in(Singleton.class);
		bind(EventBus.class).to(SimpleEventBus.class).in(Singleton.class);
		bind(PlaceController.class).toProvider(PlaceControllerProvider.class).in(Singleton.class);
	}
}

GINでオブジェクトを取得する

実際にオブジェクトがインジェクトされた状態のContactsActivityを取得するためには、以下のようにGinjectorを継承したクラスを用意して、

@GinModules(ContactsModule.class)
public interface ContactsGinjector extends Ginjector{
	ContactsActivity getContactsActivity();
}

GWT.createで生成したGinjectorを経由して取得します。

ContactsGinjector contactsGinjector = GWT.create(ContactsGinjector.class);
ContactsActivity contactsGinjector.getContactsActivity();

Guiceであれば、以下のようなコードになると思いますが、GWTでは実行時にリフレクションが使用できないので、このようなコードになるようです。

Guice.getInjector().get(ConstantsActivity.class);

RPCサービスをインジェクトする

GINでは、RPCサービス(例のContactsServiceAsync)は、GWT.createを呼び出してインジェクトしてくれます。
また、インジェクトしたいクラスが見つからない場合にも、自動的にフォールバックしてGWT.create(対象クラス)が呼び出されます。

Providerを使用する

上記の例のPlaceControllerのように、デフォルトコンストラクタがなかったり@Injectを付けられないようなクラスのオブジェクトを提供するために、Providerを使用します。

public class PlaceControllerProvider implements Provider<PlaceController> {
	private EventBus eventBus;

	@Inject
	public PlaceControllerProvider(EventBus eventBus){
		this.eventBus = eventBus;
	}

	@Override
	public PlaceController get() {
		return new PlaceController(eventBus);
	}
}

この例のEventBusもGINによりインジェクトされます。

まとめ

GWTのMVPパターンは、必要なオブジェクトが多く管理が面倒なのでGINを使ってそれらのオブジェクトをイジェクトすると多少は楽になると思います。上記の例ではActivityをGinjectorから取得していますが、もう少し広範にGINを使用するようにしたContactsサンプルをBitbucketにおいてあります。