GroovyDelegateInterceptor
なんか昨日の日記の追記と矛盾するけどgroovyスクリプトにインタフェースを実装させるのは面倒くさい。
interfaceをimplementsする場合、メソッドのシグネチャはインタフェースと厳密に一致しなければいけない。アクセス修飾子、戻り値、メソッド名、引数の型と数、throws宣言など。それにインタフェースで宣言されているメソッドすべてを実装しなければいけない。でもそんなにいっぱい書くのめんどくさい、せっかくスクリプトなのに。そこでDelegateInterceptor!diconからお手軽にgroovyスクリプトを呼び出そう。
package study.seasar; import groovy.lang.GroovyClassLoader; import java.io.File; import java.io.IOException; import org.codehaus.groovy.control.CompilationFailedException; import org.seasar.framework.aop.interceptors.DelegateInterceptor; import org.seasar.framework.exception.IORuntimeException; import org.seasar.framework.exception.IllegalAccessRuntimeException; import org.seasar.framework.exception.InstantiationRuntimeException; import org.seasar.framework.util.ResourceUtil; public class GroovyDelegateInterceptor extends DelegateInterceptor { private String path_; public GroovyDelegateInterceptor() { } public GroovyDelegateInterceptor(String path) { setGroovyScriptPath(path); } public Object getGroovyScriptPath() { return path_; } public void setGroovyScriptPath(String path) { path_ = path; Class clazz = createClass(path_); Object obj; try { obj = clazz.newInstance(); } catch (InstantiationException ex) { throw new InstantiationRuntimeException(clazz, ex); } catch (IllegalAccessException ex) { throw new IllegalAccessRuntimeException(clazz, ex); } setTarget(obj); } private Class createClass(String groovyPath) { GroovyClassLoader groovyLoader = new GroovyClassLoader(getClass().getClassLoader()); File file = ResourceUtil.getResourceAsFile(groovyPath); try { return groovyLoader.parseClass(file); } catch (CompilationFailedException e) { throw new RuntimeException(e); } catch (IOException e) { throw new IORuntimeException(e); } } }
public interface Hoge{ Object hoge(); String foo() throws IOException; int add(int a, int b); int sub(int a, int b); }
- hogeFake.groovy groovyスクリプト。インタフェースとメソッド名称と引数の数さえあっていれば呼び出せる。
import java.io.* class hogeFake { hoge() { return "hoge method" } foo() { return new test().poo() } add(i, j) { return i + j } } class test { poo() { "poo" } }
"study/seasar/hogeFake.groovy"
- Client.java クライアントはこんなカンジ。インタフェースさえ見とけばいい。
package study.seasar; import java.io.IOException; import org.seasar.framework.container.S2Container; import org.seasar.framework.container.factory.S2ContainerFactory; public class Client { private static final String PATH = "study/seasar/delegate.dicon"; public static void main(String[] args) { S2Container container = S2ContainerFactory.create(PATH); container.init(); try { Hoge hoge = (Hoge)container.getComponent(Hoge.class); System.out.println(hoge.hoge()); try { System.out.println(hoge.foo()); } catch (IOException e) { System.out.println(e.getMessage()); } System.out.println(hoge.add(40, 80)); } finally { container.destroy(); } } }
- 実行結果
hoge method
poo
120
表示した値があまりに面白みがないのは、まあ気にしない。
インタフェース経由で呼び出せば取替えきくし、とりあえず動かすというときには便利だと思う。あれ、でもこれじゃgroovyから生成したクラスにDIできなくなるのか?