Java6でclosure(クロージャ)を実現する方法。

とりあえず、実現方法その1はJavaScriptで実装すればよい。

以下ソース

/*
 * 作成日 (creation date)  :2008/12/06
 * パッケージ  (package name) :test
 * ファイル名  (file name)    :TestJs.java
 */
package test;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.io.StringReader;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.reflect.Field;

import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;


/**
 * <i>概要(abstract)</i>: JSテスト
 * .<p>
 * JSテスト
 * 
 *
 * @author  kensir0u
 * @version 1.0
 * @since   JDK 6.0
 *
 */
public class TestJs {
	
	public int x = 100;
	
	@JScript(
	"function gerClosure(_this) {" + 
		"var inner = 2;"+ 
		
		"function invoke(param) {"+ 
		"	return inner * _this.x * param;"+ 
		"}"+ 
		
		"return invoke;"+ 
	"}" +	
	"var invoke = gerClosure(_this);" + 
	"String(parseInt(invoke(_param)));  "     
	)
	private String script;
	
	public static void main(String[] args) {
		String o = getClosure("script").invoke(3);
		System.out.println(o);
	}
	
	public static TestJs getClosure(String closureName){
		TestJs js = new TestJs();
		js.script = closureName;
		return js;
	}
	
	@SuppressWarnings("unchecked")
	public <T>T invoke(int param){
		String script = getScript(this.script);
		ScriptEngineManager manager = new ScriptEngineManager();
		ScriptEngine se = manager.getEngineByName("js");
		
		if (se != null) {
			Bindings bind = se.getBindings(ScriptContext.ENGINE_SCOPE);
			bind.put("_this", this);
			bind.put("_param",param);
			StringReader sr = new StringReader(script);
			try{
				Object result = se.eval(sr);
				return (T)result;
			} catch (Exception e){
				throw new RuntimeException(e);
			}finally{ sr.close();}
		} else {
			return null;
		}
	}
	
	private static String getScript(String fieldName){
		try {
			Field f= TestJs.class.getDeclaredField(fieldName);
			JScript js = f.getAnnotation(JScript.class);
			return js.value();
		} catch (Exception e) {}
		return null;
	}
	
	@Target({ METHOD, FIELD })
	@Retention(RUNTIME)
	@interface JScript{
		String value();
	}
}