Skip to content

Instantly share code, notes, and snippets.

@orekyuu
Created April 9, 2016 14:54
Show Gist options
  • Select an option

  • Save orekyuu/e113d3a5ff963eb3e13c0fce2632d5f7 to your computer and use it in GitHub Desktop.

Select an option

Save orekyuu/e113d3a5ff963eb3e13c0fce2632d5f7 to your computer and use it in GitHub Desktop.
Proxyで遊んだ。 出力 3.0 ab
package demo;
import net.orekyuu.JavaScriptBinder;
import javax.script.ScriptException;
public class Main {
public static void main(String[] args) throws ScriptException {
TestJs testJs = JavaScriptBinder.create(TestJs.class);
double sumInt = testJs.sum(1, 2);
System.out.println(sumInt);
String sumStr = testJs.sum("a", "b");
System.out.println(sumStr);
}
}
package demo;
import net.orekyuu.annotation.Function;
import net.orekyuu.annotation.ScriptFile;
@ScriptFile("/test.js") // resources/test.jsを使用する
public interface TestJs {
@Function("sum") //アノテーションで指定したtest.jsにある関数を呼び出す
String sum(String a, String b);
//アノテーションがなければメソッド名と同じ関数を呼び出し
double sum(int a, int b);
@Function("hello")
String hello();
@Function("append")
String append();
}
package net.orekyuu.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Function {
/**
* @return 呼び出す関数名
*/
String value();
}
package net.orekyuu.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ScriptFile {
/**
* @return ロードするスクリプトファイル
*/
String value();
}
package net.orekyuu;
import net.orekyuu.annotation.ScriptFile;
import net.orekyuu.script.ScriptRunner;
import javax.script.*;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Proxy;
import java.util.Objects;
public class JavaScriptBinder {
private JavaScriptBinder() {
throw new UnsupportedOperationException();
}
public static <T> T create(Class<T> t, InputStream stream) throws ScriptException {
Objects.requireNonNull(stream, "inputStream is null");
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine js = manager.getEngineByName("js");
if (js instanceof Compilable) {
CompiledScript compile = ((Compilable) js).compile(new InputStreamReader(stream));
compile.eval();
js = compile.getEngine();
} else {
js.eval(new InputStreamReader(stream));
}
return create(t, js);
}
public static <T> T create(Class<T> t) throws ScriptException {
ScriptFile annotation = t.getAnnotation(ScriptFile.class);
if (annotation == null) {
throw new IllegalArgumentException("ScriptFileアノテーションが見つかりません");
}
String value = annotation.value();
if (value == null) {
throw new IllegalArgumentException("ファイルを指定してください");
}
return create(t, t.getResourceAsStream(value));
}
@SuppressWarnings("unchecked")
private static <T> T create(Class<T> t, ScriptEngine engine) {
return (T) Proxy.newProxyInstance(t.getClassLoader(), new Class[]{t}, new ScriptRunner(engine));
}
}
package net.orekyuu.script;
import net.orekyuu.annotation.Function;
import javax.script.*;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class ScriptRunner implements InvocationHandler {
private ScriptEngine engine;
public ScriptRunner(ScriptEngine engine) {
this.engine = engine;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Function annotation = method.getDeclaredAnnotation(Function.class);
String functionName = method.getName();
if (annotation != null) {
functionName = annotation.value();
}
if (engine instanceof Invocable) {
return ((Invocable) engine).invokeFunction(functionName, args);
}
return null;
}
}
/**
* Created by orekyuu on 2016/04/09.
*/
function sum(a, b) {
return a + b;
}
function hello() {
return "hello";
}
function append(str) {
return str + 'a';
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment