JDK 1.6 中的 JavaCompiler:如何将类字节直接写入 byte[] 数组?
所以我最近了解了新的 JavaCompiler API 在 JDK 1.6 中可用。这使得直接从运行代码将 String
编译为 .class
文件变得非常简单:
String className = "Foo";
String sourceCode = "...";
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
List<JavaSourceFromString> unitsToCompile = new ArrayList<JavaSourceFromString>()
{{
add(new JavaSourceFromString(className, sourceCode));
}};
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
compiler.getTask(null, fileManager, null, null, null, unitsToCompile).call();
fileManager.close();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
FileInputStream fis = new FileInputStream(className + ".class");
IOUtils.copyStream(fis, bos);
return bos.toByteArray();
您可以从 JavaSourceFromString
获取源代码a href="http://java.sun.com/javase/6/docs/api/javax/tools/JavaCompiler.html" rel="nofollow noreferrer">Javadoc。
这将非常方便地将当前工作目录中的 sourceCode
编译为 Foo.class
。
我的问题是:是否可以直接编译为 byte[]
数组,并完全避免处理 File
I/O 的混乱?
So I recently learned of the new JavaCompiler API available in JDK 1.6. This makes it very simple to compile a String
to a .class
file directly from running code:
String className = "Foo";
String sourceCode = "...";
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
List<JavaSourceFromString> unitsToCompile = new ArrayList<JavaSourceFromString>()
{{
add(new JavaSourceFromString(className, sourceCode));
}};
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
compiler.getTask(null, fileManager, null, null, null, unitsToCompile).call();
fileManager.close();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
FileInputStream fis = new FileInputStream(className + ".class");
IOUtils.copyStream(fis, bos);
return bos.toByteArray();
You can grab the source to JavaSourceFromString
from the Javadoc.
This will very handily compile sourceCode
to Foo.class
in the current working directory.
My question is: is it possible to compile straight to a byte[]
array, and avoid the messiness of dealing with File
I/O altogether?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
也许您可以创建自己的 javax.tools.JavaFileManager 实现类,在其中返回您自己的 javax.tools.FileObject 实现,然后将其写入内存而不是磁盘。因此,对于
javax.tools.FileObject
的子类Writer openWriter() throws IOException
方法,您将返回一个java.io.StringWriter
。所有方法都应转换为其对应的String
方法。Maybe you could create your own
javax.tools.JavaFileManager
implementing class where you would return your own implementation ofjavax.tools.FileObject
which would then write it out to memory instead to disk. So for your subclass ofjavax.tools.FileObject
Writer openWriter() throws IOException
method you would return ajava.io.StringWriter
. All the methods should be converted to theirString
counterparts.没有标准 API 将字节码写入字节数组的原因是编译单个 Java 源文件可能会产生多个字节码文件。例如,任何具有嵌套/内部/匿名类的源文件都将生成多个字节码文件。
如果您推出自己的 JavaFileManager,则需要处理这种情况。
The reason that there is no standard API to write bytecodes to a byte array is that compiling a single Java source file may result in multiple bytecode files. For example, any source file with nested / inner / anonymous classes will result in multiple bytecode files.
If you roll your own JavaFileManager, you will need to deal with this situation.
JSR 199 API 附带的演示应用程序有一个内存中的字符串编译示例(它确实使用了
MemoryFileManager
)。也许看一下此处 或 此处(不过这些示例有点过时,需要稍作更改)。也可以检查如何即时编译? Java.net 上的文章。PS:我没有查看所有细节,但我认为它不能处理 Stephen C。
The demo application that shipped with the JSR 199 API had an in-memory compile-from-string example (which is indeed using a
MemoryFileManager
). Maybe have a look at it here or here (these samples are a bit outdated though, they will require slight changes). Also maybe check the How to compile on the fly? article on Java.net.PS: I didn't look at all the details, but I'm don't think it handles the cases mentioned by Stephen C.