Post date: Jun 30, 2015 12:05:44 PM
eval関数をjavascriptから持ってきてつかうことはやったが,
せっかくなのでちゃんとjavaのクラスとか呼び出したいよね,というのに対応してみた.
リフレクション使えばいい.(全く効率的ではない)
import java.io.File; import java.io.FileWriter; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import javax.tools.ToolProvider; public class Eval { final private String className = "EvalTmp";//被らなさそうな名前で private String path = null;//コンパイル後のデータ保管場所 private Class<?> superClass = null; public Eval(Object obj, String path) { this.path = ((path.endsWith("\\") || path.endsWith("/"))) ? path : path + "/"; superClass = (obj != null) ? obj.getClass() : null; } public Eval(Object obj) { this(obj, "../"); } public Object eval(String str) { //適当に引数の内容を返すstaticメソッド をもつクラスを定義 StringBuilder sb = new StringBuilder(); sb.append("public class "); sb.append(className); if (superClass != null) { sb.append(" extends "); sb.append(superClass.getName()); } sb.append(" { public static Object test(){"); sb.append("return ("); sb.append(str); sb.append(");}}"); String fullPath = path + className + ".java"; //javaファイルに保存 そしてコンパイル実行 saveString(sb.toString(), fullPath); try { int ret = ToolProvider.getSystemJavaCompiler().run(null, null, null, new String[] { fullPath }); ClassLoader loader = URLClassLoader.newInstance( new URL[] { new File(path).toURI().toURL() }, (superClass != null) ? superClass.getClassLoader() : null); Class<?> clazz = Class.forName(className, true, loader); Method method = clazz.getMethod("test", null); return method.invoke(null, null); } catch (Exception e) { e.printStackTrace(); } return null; } private void saveString(String str, String path) { try { File file = new File(path); FileWriter filewriter = new FileWriter(file); filewriter.write(str); filewriter.close(); } catch (Exception e) { } } }
evalメソッドの引数を用いたjavaファイルを作ってそれをコンパイルしているだけ.
自分で作っておいて何だが,いくらjavaがコンパイル速いからといってもこれは無いと思う.
いちいちjavaファイル書き出す必要があるのでどっか適当な場所に保存する.
一応使い方も載せておく.
引数で実行元のインスタンスを渡せばインナークラス程度なら呼び出して使えるようにした.
public class Main extends Main1 { public static void main(String[] args) { Eval eval = new Eval(null); System.out.println(eval.eval("new String(\"test\")")); new Main().test(); } void test() { Eval eval = new Eval(this); A a = (A) eval.eval("new A()"); a.a(); } } class Main1 { public static class A { void a() { System.out.println("a"); } } }
同じやり方を取るにしてももっとやり方がある気もする.
なんかバイトコードいじったりしてみたい.