18

如何从 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 的建议——它真的很有效。

4

6 回答 6

10

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

任何理由这不应该工作?


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

此外,设置javac设置,如您的情况下的类路径,可以通过setCustomArguments(String[] pCustomArguments)JavacJavaCompilerSettings课堂上完成。

于 2009-03-05T20:52:57.690 回答
8

您可能还想看看 Janino。

从他们的网站:

Janino 是一个编译器,它读取 JavaTM 表达式、块、类主体、源文件或一组源文件,并生成直接加载和执行的 JavaTM 字节码。Janino 并不是一个开发工具,而是一个用于运行时编译目的的嵌入式编译器,例如表达式评估器或像 JSP 这样的“服务器页面”引擎。

http://www.janino.net/

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

于 2009-03-05T21:32:06.270 回答
3

如果你不完全依赖于编译,像 Beanshell、groovy 和其他脚本语言这样的解决方案很容易嵌入(事实上,java 内置了对插入脚本语言的支持,所以你的代码甚至不知道是什么语言脚本写在)

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

于 2009-03-05T21:08:58.230 回答
1

Javassist可能会让您感兴趣

于 2009-03-05T20:49:50.507 回答
0

在 Tomcat 等 Web 容器中运行,首先生成一个 JSP 页面,然后调用它。

这也允许您通过简单地覆盖 JSP 页面而不是让您的类加载器缓慢运行满来摆脱旧的类定义。

“内存”要求是由于速度还是由于不更改代码库?

于 2009-03-05T21:39:35.927 回答
0

ECJ Eclipse Java 编译器

Eclipse 提供并使用它自己的编译器,它不是 javac

  • Eclipse 编译器在 IDE (Eclipse) 内部使用
  • Eclipse 编译器也可以用作 Eclipse 之外的纯批处理编译器

编译源文件

$ java -jar ecj-3.5.2.jar HelloWorld.java

于 2013-12-13T18:04:51.673 回答