JavaCompiler из JDK 1.6: как записать байты класса непосредственно в массив 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 из Javadoc.

Это очень удобно скомпилирует sourceCode в Foo.class в текущем рабочем каталоге.

Мой вопрос: возможно ли скомпилировать прямо в массив byte[] и вообще избежать путаницы с File вводом-выводом?


person George Armhold    schedule 25.01.2010    source источник


Ответы (3)


Возможно, вы могли бы создать свой собственный класс реализации javax.tools.JavaFileManager, в котором вы бы вернули свою собственную реализацию javax.tools.FileObject, которая затем записала бы ее в память, а не на диск. Таким образом, для вашего подкласса метода javax.tools.FileObject Writer openWriter() throws IOException вы должны вернуть java.io.StringWriter. Все методы должны быть преобразованы в их String аналоги.

person Turing    schedule 25.01.2010

Причина отсутствия стандартного API для записи байт-кодов в массив байтов заключается в том, что компиляция одного исходного файла Java может привести к созданию нескольких файлов байт-кода. Например, любой исходный файл с вложенными/внутренними/анонимными классами приведет к созданию нескольких файлов байт-кода.

Если вы создадите свой собственный JavaFileManager, вам придется иметь дело с этой ситуацией.

person Stephen C    schedule 25.01.2010

Демонстрационное приложение, поставляемое с API JSR 199, имело пример компиляции из строки в памяти (который действительно использует MemoryFileManager). Может быть, взгляните на это здесь или здесь (хотя эти примеры немного устарели, они потребуют небольших изменений). Также, возможно, проверьте Как компилировать на лету? статья на Java.net.

PS: я не смотрел на все детали, но я не думаю, что он обрабатывает случаи, упомянутые Стивен С.

person Pascal Thivent    schedule 25.01.2010