SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事

DIをスクリプト言語で実装する

XMLの代わりにスクリプト言語を利用してDIの注入定義を行う

JavaScript(Java SE 6)を用いた実装

 JavaScriptで定義したオブジェクトをJSR223で定義されているAPIを用いてJavaのコード側で取得し実行します。

実行クラスの作成

 「di.js」ファイルにTestContainerインターフェイスを実装した定義が記述されているものとして実行クラスを作成します。

AppMainJs.java
import java.io.*;
import javax.script.*;

public class AppMainJs {

    public static void main(String[] args) {

        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByExtension("js");

        try {
            engine.eval(new FileReader("di.js"));
            Invocable inv = (Invocable)engine;

            TestContainer tc = inv.getInterface(TestContainer.class);

            Service service = (Service)tc.getComponent("service");
            service.service();

        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

コンパイル

 上記までに作成した実行クラス、共通インターフェイス・クラスすべてをJava SE 6環境のjavacでコンパイルします。

  • コンパイル対象
    • Service.java
    • MultiService.java
    • PrintService.java
    • TestContainer.java
    • AppMainJs.java
 Java SE 6 beta2 b81でコンパイルが正常に終了する事を確認しています。

JavaScriptでDIを定義

 JavaScript側でJavaのインターフェイスを実装するために、インターフェイスで定義されているメソッドと同じ名称・同じ引数のメソッドを定義します。

 JavaScriptでPackages.パッケージ名.クラス名の記述を行うことで、Javaのクラスが使用できます。

di.js
//DI の定義
var mservice = new Packages.MultiService();
mservice.addService(new Packages.PrintService(
    "print javascript service 1"));
mservice.addService(new Packages.PrintService(
    "print javascript service 2"));
mservice.addService(new Packages.PrintService(
    "print javascript service 3"));

var table = new Packages.java.util.HashMap();
table.put("service", mservice);

//TestContainer インターフェイスの実装部分
function getComponent(name) {
    return table.get(name);
}

実行

 カレントフォルダに「di.js」ファイルを配置して、Java SE 6のjavaコマンドで実行クラスを実行します。

実行例
>java AppMainJs

 結果は次のようになり、JavaScriptで記述したオブジェクト定義をJavaから使用しています。

出力結果
print javascript service1
print javascript service2
print javascript service3
 出力結果はJava SE 6 beta2 b81環境での実行結果です。

Groovy(J2SE 5.0)を用いた実装

 Groovyで定義したクラスをJavaのコード側でインスタンス化し実行します。

実行クラスの作成

 「di.groovy」ファイルにTestContainerインターフェイスを実装したクラス定義が記述されているものとして実行クラスを作成します。

 GroovyClassLoaderを使用して「di.groovy」ファイルに記述しているTestContainerの実装クラスを取得しインスタンス化、DIされたオブジェクトを取得し実行します。

AppMainGroovy.java
import java.io.*;
import groovy.lang.GroovyClassLoader;

public class AppMainGroovy {
    public static void main(String[] args) {

        GroovyClassLoader loader = new GroovyClassLoader();

        try {
            Class<TestContainer> cl 
                = loader.parseClass(new File("di.groovy"));

            TestContainer tc = cl.newInstance();

            Service service = (Service)tc.getComponent("service");
            service.service();

        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

コンパイル

 上記までに作成した実行クラス、共通インターフェイス・クラスすべてをJ2SE 5.0のjavacでコンパイルします。

 なお、クラスパスにGroovyのインストール先フォルダ内の「groovy-1.0-jsr-05.jar」ファイルを追加しておきます。

  • コンパイル対象
    • Service.java
    • MultiService.java
    • PrintService.java
    • TestContainer.java
    • AppMainGroovy.java

GroovyでDIを定義

 GroovyスクリプトでTestContainerインターフェイスを実装したクラスを定義します。

di.groovy
class GroovyContainer implements TestContainer{
    @Property table

    def GroovyContainer() {
        //DI の定義
        def service = new MultiService();
        service.addService(new PrintService("print groovy service 1"));
        service.addService(new PrintService("print groovy service 2"));
        service.addService(new PrintService("print groovy service 3"));

        table = new HashMap()
        table["service"] = service;
    }

    def Object getComponent(String name) {
        return table[name]
    }
}

実行

 カレントフォルダに「di.groovy」ファイルを配置してJ2SE 5.0のjavaコマンドで実行クラスを実行します。

 なお、クラスパスにGroovyのインストール先フォルダ内の「groovy-1.0-jsr-05.jar」、同libフォルダ内の「asm-2.2.jar」と「antlr-2.7.5.jar」ファイルを追加しておきます。

実行例
>java AppMainGroovy

 結果は次のようになり、Groovyで記述したクラス定義をJavaで使用しています。

出力結果
print groovy service1
print groovy service2
print groovy service3

まとめ

 XMLでDIを定義する代わりに、スクリプト言語を使った単純なDI処理を実装してみました。

 現時点では実用性の判断は困難ですが、アノテーションやCoC(Convention over Configuration)を用いたDI定義の削減とは別のアプローチとして、こういう方法もありかなと考えています。

 また、JSR223の活用手段を考える上でも有効な発想であると考えています。

参考資料

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
特集記事連載記事一覧

もっと読む

この記事の著者

和田 好朗(ワダ ヨシアキ)

ITアーキテクト目指して奮闘中。新技術には目が無い技術者。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/386 2006/05/29 12:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー