JavaScript(Java SE 6)を用いた実装
JavaScriptで定義したオブジェクトをJSR223で定義されているAPIを用いてJavaのコード側で取得し実行します。
実行クラスの作成
「di.js」ファイルにTestContainerインターフェイスを実装した定義が記述されているものとして実行クラスを作成します。
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
JavaScriptでDIを定義
JavaScript側でJavaのインターフェイスを実装するために、インターフェイスで定義されているメソッドと同じ名称・同じ引数のメソッドを定義します。
JavaScriptでPackages.パッケージ名.クラス名の記述を行うことで、Javaのクラスが使用できます。
//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
Groovy(J2SE 5.0)を用いた実装
Groovyで定義したクラスをJavaのコード側でインスタンス化し実行します。
実行クラスの作成
「di.groovy」ファイルにTestContainerインターフェイスを実装したクラス定義が記述されているものとして実行クラスを作成します。
GroovyClassLoaderを使用して「di.groovy」ファイルに記述しているTestContainerの実装クラスを取得しインスタンス化、DIされたオブジェクトを取得し実行します。
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インターフェイスを実装したクラスを定義します。
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の活用手段を考える上でも有効な発想であると考えています。
