Java 5 和 Java 6 的即时、内存中 Java 代码编译

问题描述 投票:0回答:6

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

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

  • 大多数依赖于 Java 6 编译器 API。
  • 那些不这样做的人,就依靠技巧。
  • 是的,我查看了 commons-jci。要么我太笨,无法理解它是如何工作的,要么就是不明白。
  • 我找不到如何向编译器提供我当前的类路径(相当大)。
  • 在有效的实现上(在 Java 6 中),我找不到如何正确加载内部类(或内部匿名类)。
  • 如果整个东西都在内存中,我会非常喜欢它,因为它可以在多个环境中运行。

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

编辑:

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

编辑2: 目前,我对 BeanShell 的“评估”感到满意。显然它做了我需要它做的一切(获取一个字符串,在“当前”类路径的上下文中评估它。它确实错过了一些 Java 5 功能,但它可以使用枚举(不是定义)和编译的“通用”(已删除) )课程,所以它应该足够满足我想要的了。

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

Edit3:接受了 beanshell 建议 - 它确实非常有效。

java compilation runtime runtime-compilation
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
 来完成。


8
投票

您可能也想看看 Janino。

来自他们的网站:

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

http://www.janino.net/

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


3
投票

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

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


1
投票

Javassist您可能会感兴趣


0
投票

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

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

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


0
投票

ECJ Eclipse Java 编译器

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

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

编译源文件


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

© www.soinside.com 2019 - 2024. All rights reserved.