JavaCompiler из JDK 1.6: как записать байты класса непосредственно в массив byte[]?
Поэтому недавно я узнал о новом API JavaCompiler, доступном в 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
из Javadoc.
Это будет очень легко скомпилировать sourceCode
в Foo.class
в текущем рабочем каталоге.
У меня вопрос: можно ли скомпилировать прямо в byte[]
массив, и избежать беспорядка иметь дело с File
I/O в целом?
3 ответа
Может быть, вы могли бы создать свой собственный javax.tools.JavaFileManager
реализующий класс, где вы бы вернули свою собственную реализацию javax.tools.FileObject
который затем записал бы это в память вместо на диск. Так что для вашего подкласса javax.tools.FileObject
Writer openWriter() throws IOException
метод вы бы вернули java.io.StringWriter
, Все методы должны быть преобразованы в их String
двойники.
Причина, по которой нет стандартного API для записи байт-кодов в байтовый массив, заключается в том, что компиляция одного исходного файла Java может привести к появлению нескольких файлов байт-кода. Например, любой исходный файл с вложенными / внутренними / анонимными классами приведет к нескольким файлам байт-кода.
Если вы свернули свой собственный JavaFileManager, вам нужно будет разобраться с этой ситуацией.
Демонстрационное приложение, поставляемое с API JSR 199, имело пример компиляции из строки в памяти (который действительно использует MemoryFileManager
). Может быть, посмотрите на это здесь или здесь (эти образцы немного устарели, хотя, они потребуют небольших изменений). Также, может быть, проверить Как собрать на лету? статья на Java.net.
PS: я не смотрел на все детали, но я не думаю, что он обрабатывает случаи, упомянутые Стивеном С.