适用于Java 5和Java 6的即时内存Java代码编译

Ran*_*ron 17 java compiler-construction runtime compilation runtime-compilation

如何从Java 5和Java 6中的任意字符串(在内存中)编译java代码,加载它并在其上运行特定方法(预定义)?

在你点燃之前,我查看了现有的实现:

  • 大多数人依赖Java 6 Compiler API.
  • 那些没有,依靠技巧.
  • 是的,我检查了commons-jci.要么我太密集了,不能理解它是如何工作的,要么就是不能.
  • 我找不到如何向编译器提供我当前的类路径(这是非常巨大的).
  • 在有效的实现上(在Java 6中),我找不到如何正确加载内部类(或内部匿名类).
  • 如果整个事物都在内存中,我会非常喜欢它,因为它在多个环境中运行.

我确信之前已经解决了这个问题,但我找不到任何看起来甚至是谷歌半生产质量的东西(除了jci,正如我之前所说,我还没有设法使用).

编辑:

  • 我查看了JavaAssist - 我需要内部类,Java 5.0语言级支持以及使用整个类路径进行编译.另外,我想动态创建新类.我可能弄错了,但我找不到如何用JavaAssit做到这一点.
  • 我愿意使用基于文件系统的解决方案(调用javac),但我不知道如何划分类路径,也不知道如何使用特殊的类加载器加载文件(不在我的类路径中)回收多次调用.虽然我知道如何研究它,但我更喜欢现成的解决方案.

Edit2:现在,我对BeanShell"评估"感到满意.显然它完成了我需要的所有东西(获取一个字符串,在'当前'类路径的上下文中评估它.它确实错过了一些Java 5特性,但它可以使用枚举(不定义)和编译'泛型'(擦除) )类,所以它应该足够我想要的.

我不想将答案标记为已接受,因为我希望有更好的解决方案出现.

Edit3:接受了beanshell建议 - 它真的很棒.

Yuv*_*dam 9

JCI看起来很好.此代码段应该是您的基础:

JavaCompiler compiler = new JavaCompilerFactory().createCompiler("eclipse");

MemoryResourceReader mrr = new MemoryResourceReader();
mrr.add("resource name string", yourJavaSourceString.getBytes());

MemoryResourceStore mrs = new MemoryResourceStore();

CompilationResult result = compiler.compile(sources, mrr, mrs);

// don't need the result, unless you care for errors/warnings
// the class should have been compiled to your destination dir
Run Code Online (Sandbox Code Playgroud)

这有什么理由不起作用?


编辑:添加了一个MemoryResourceStore将编译后的类输出发送到内存,就像请求一样.

此外,设置javac设置,如您的案例中的类路径,可以setCustomArguments(String[] pCustomArguments)JavacJavaCompilerSettings课堂上完成.


Bil*_*son 7

您也可以查看Janino.

从他们的网站:

Janino是一个编译器,它读取JavaTM表达式,块,类主体,源文件或一组源文件,并生成直接加载和执行的JavaTM字节码.Janino不是一个开发工具,而是一个用于运行时编译目的的嵌入式编译器,例如表达式求值程序或JSP之类的"服务器页面"引擎.

http://www.janino.net/

我目前正在一个非常大的任务关键项目中使用它,它工作得很好


Bil*_*l K 3

如果您没有完全依赖于编译,则可以轻松嵌入 Beanshell、groovy 和其他脚本语言等解决方案(事实上,java 内置了对插入脚本语言的支持,因此您的代码甚至不知道是什么语言脚本写在)

Beanshell 应该运行任何 100% java 代码 IIRC,而且我相信 Groovy 可以运行大多数 java 代码——可能是全部。