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

发布于 2024-07-14 18:53:47 字数 962 浏览 4 评论 0原文

如何从 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 建议。 - 它确实非常有效。

How can I compile java code from an arbitrary string (in memory) in Java 5 and Java 6, load it and run a specific method on it (predefined)?

Before you flame this, I looked over existing implementations:

  • Most rely on Java 6 Compiler API.
  • Those that don't, rely on tricks.
  • Yes, I checked out commons-jci. Either I'm too dense to understand how it works, or it just doesn't.
  • I could not find how to feed the compiler my current class path (which is quite huge).
  • On the implementation that worked (in Java 6), I could not find how to correctly load inner classes (or inner anonymous classes).
  • I'd quite like it if the entire thing was in-memory, as the thing runs on multiple environments.

I'm sure this has been solved before, but I can't find anything that looks even half-production quality on google (except jci, which, as I've said before, I haven't managed to use).

Edit:

  • I looked over JavaAssist - I need inner classes, Java 5.0 language level support and compiling with the entire classpath. Also, I'd like to create new classes on the fly. I
    might be mistaken, but I couldn't find how to do this with JavaAssit.
  • I'm willing to use a file-system based solution (calling javac) but I don't know how to divine the classpath, nor how to later load the files (which are not in my classpath) with a special classloader that can be recycled for multiple invocations. While I do know how to research it, I'd prefer a ready solution.

Edit2:
For now, I'm content with BeanShell "evaluate". Apparently it does everything I need it to (get a string, evaluate it in the context of the 'current' classpath. It does miss some of Java 5 features, but it can use enums (not define) and compiled 'generic' (erased) classes, so it should be enough for what I want.

I don't want to mark the answer as accepted yet since I do hope for a better solution to come up.

Edit3: Accepted the beanshell suggestion - it really works wonderfully.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

世俗缘 2024-07-21 18:53:47

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: added a MemoryResourceStore to send the compiled class output to memory, like requested.

此外,设置 javac 设置(例如您的情况下的类路径)可以通过 setCustomArguments(String[] pCustomArguments) in JavacJavaCompilerSettings班级。

JCI looks fine. This code snippet should be your base:

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

Any reason this should not work?


Edit: added a MemoryResourceStore to send the compiled class output to memory, like requested.

Also, setting javac settings, like classpath in your case, can be done via setCustomArguments(String[] pCustomArguments) in JavacJavaCompilerSettings class.

以酷 2024-07-21 18:53:47

您可能还想看看 Janino。

从他们的网站来看:

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

http://www.janino.net/

我目前在一个相当大的关键任务项目中使用它并且它有效正好

You might want to check out Janino as well.

From their website:

Janino is a compiler that reads a JavaTM expression, block, class body, source file or a set of source files, and generates JavaTM bytecode that is loaded and executed directly. Janino is not intended to be a development tool, but an embedded compiler for run-time compilation purposes, e.g. expression evaluators or "server pages" engines like JSP.

http://www.janino.net/

Im currently using it in a pretty large mission critical project and it works just fine

寻找一个思念的角度 2024-07-21 18:53:47

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

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

If you're not completely tied to compiling, solutions like Beanshell, groovy and the other scripting languages are easily embedded (in-fact, java has built-in support for plugging in a scripting language so your code doesn't even know what language the script is written in)

Beanshell should run any 100% java code IIRC, and I believe Groovy can run most java code--possibly all.

回忆那么伤 2024-07-21 18:53:47

Javassist 您可能感兴趣

Javassist might interest you

殤城〤 2024-07-21 18:53:47

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

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

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

Run inside a web container like Tomcat and first generate a JSP page, and then invoke it.

This also allow you to get rid of the old class definitions by simply overwriting the JSP page instead of having your classloader slowly run full.

Is the "in-memory" requirement due to speed or due to not changing the code base?

ぽ尐不点ル 2024-07-21 18:53:47

ECJ Eclipse Java 编译器

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

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

编译源文件


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

ECJ Eclipse Java Compiler

Eclipse provides and uses its own compiler that is not javac

  • The Eclipse compiler is used inside the IDE (Eclipse)
  • The Eclipse compiler can also be used as a pure batch compiler
    outside of Eclipse

Compile a source file


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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文