动态地,针对Java5和Java6的内存中java代码编译

动态地,针对Java5和Java6的内存中java代码编译,java,compiler-construction,runtime,compilation,runtime-compilation,Java,Compiler Construction,Runtime,Compilation,Runtime Compilation,如何从java 5和java 6中的任意字符串(内存中)编译java代码,加载它并在其上运行特定方法(预定义) 在此之前,我查看了现有的实现: 大多数依赖于Java6编译器API 那些不这样做的人,依靠诡计 是的,我查过commons jci。要么我太笨了,不明白它是怎么工作的,要么就是不明白 我找不到如何将我当前的类路径(相当大)提供给编译器 在有效的实现(Java6)中,我找不到如何正确加载内部类(或内部匿名类) 我非常希望整个东西都在内存中,因为它可以在多个环境中运行 我确信这个问题以

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

在此之前,我查看了现有的实现:

  • 大多数依赖于Java6编译器API
  • 那些不这样做的人,依靠诡计
  • 是的,我查过commons jci。要么我太笨了,不明白它是怎么工作的,要么就是不明白
  • 我找不到如何将我当前的类路径(相当大)提供给编译器
  • 在有效的实现(Java6)中,我找不到如何正确加载内部类(或内部匿名类)
  • 我非常希望整个东西都在内存中,因为它可以在多个环境中运行
我确信这个问题以前已经解决了,但我在谷歌上找不到任何看起来甚至是一半生产质量的东西(除了jci,正如我之前所说,我还没有设法使用jci)

编辑:

  • 我查看了JavaAssist—我需要内部类、Java 5.0语言级别的支持以及使用整个类路径进行编译。此外,我还想动态创建新类。我 可能是弄错了,但我找不到如何使用JavaAssit实现这一点
  • 我愿意使用基于文件系统的解决方案(称为javac),但我不知道如何预测类路径,也不知道以后如何使用可循环多次调用的特殊类加载器加载文件(不在我的类路径中)。虽然我知道如何研究它,但我更喜欢现成的解决方案
编辑2: 现在,我对比恩希尔的“评估”很满意。显然,它做了我所需要的一切(获取一个字符串,在“当前”类路径的上下文中对其求值。它确实缺少Java 5的一些功能,但它可以使用枚举(而不是定义)和编译的“泛型”(擦除)类,所以它应该足以满足我的需要

我不想把答案标记为已被接受,因为我确实希望找到更好的解决方案


Edit3:接受了beanshell的建议-它真的非常有效。

您可能会感兴趣

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
有什么理由不应该这样做吗?
Edit:添加了一个
MemoryResourceStore
来将编译后的类输出发送到内存,就像请求的那样


另外,设置
javac
设置,如本例中的类路径,可以通过
JavacJavaCompilerSettings
类来完成。

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


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

您可能还想查看Janino

从他们的网站:

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


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

在像Tomcat这样的web容器中运行,首先生成一个JSP页面,然后调用它

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

“内存中”的要求是由于速度还是由于不改变代码基础?

Eclipse提供并使用自己的非javac编译器

  • Eclipse编译器在IDE(Eclipse)中使用
  • Eclipse编译器也可以用作纯批处理编译器 日食之外
编译源文件


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

没有理由,但是:1.我不知道如何预测类路径。正如我前面所说的,它庞大而复杂。我希望编译器使用“内存中”的类编译。2.我将使用文件输出作为最后手段,但我想首先探索内存中的解决方案。我查看了JavaAssist,但它并不完全是我想要的。我想运行作为字符串提供给我的代码,依赖于我的类的代码-我找不到使用JavaAssist实现这一点的方法。另外,JavaAssist的局限性(没有5.0功能)对我来说是非常有限的。忘了提一下。我确实查看了Janino。正如我所说,我需要5.0功能才能与现有代码进行互操作。Janino支持一些5.0功能,我只是不确定它是否能满足您的需要。祝您好运;我很想听听您的意见。Janino似乎比BeanShell高得多。1.5 f太糟糕了eatures。事实上,到目前为止,我一直使用这种方法。它很笨重,但很有效。但是,我讨厌它,客户也不信任它。我宁愿使用更干净(或更好的隐藏)的方法。我敢打赌,你会更讨厌类加载器问题;-)要非常小心:)这是一个很好的解决方案,但我仍然希望有一个更好的版本,有一个真正的编译过程。如果没有其他事情发生,我会把这个标记为接受。谢谢。你知道,我想这个API一直都是可用的:但它不在java中。因此,随着变化(尽管我认为变化不大),我并不是说这对每个人都是正确的解决方案,但它完全符合我的需要。BSH2.0真的能创造奇迹。