На лету, компиляция Java-кода в памяти для Java 5 и Java 6
Как я могу скомпилировать java-код из произвольной строки (в памяти) в Java 5 и Java 6, загрузить ее и запустить на ней определенный метод (предопределенный)?
Прежде чем вы начнете плакать, я просмотрел существующие реализации:
- Большинство полагаются на API компилятора Java 6.
- Те, кто этого не делает, полагаются на трюки.
- Да, я проверил commons-jci. Либо я слишком плотный, чтобы понять, как это работает, либо просто не работает.
- Я не мог найти, как передать компилятор моему текущему пути к классу (который довольно большой).
- В реализации, которая работала (в Java 6), я не мог найти, как правильно загружать внутренние классы (или внутренние анонимные классы).
- Мне бы очень понравилось, если бы все было в памяти, так как все работает в нескольких средах.
Я уверен, что это было решено раньше, но я не могу найти ничего, что бы выглядело даже полупроизводственного качества в google (кроме jci, который, как я уже говорил, мне не удалось использовать).
Изменить:
- Я просмотрел JavaAssist - мне нужны внутренние классы, поддержка языкового уровня Java 5.0 и компиляция с помощью всего пути к классам. Кроме того, я хотел бы создавать новые классы "на лету". я
может быть ошибочно, но я не мог найти, как это сделать с помощью JavaAssit.
- Я хочу использовать решение на базе файловой системы (вызов javac), но я не знаю, как божественный путь к классам, и как позже загружать файлы (которые не входят в мой путь к классам) со специальным загрузчиком классов которые могут быть переработаны для нескольких вызовов. Хотя я действительно знаю, как его исследовать, я бы предпочел готовое решение.
Edit2:
На данный момент я доволен тем, что BeanShell "оценивает". По-видимому, он делает все, что мне нужно (получить строку, оценить ее в контексте "текущего" класса. Он пропускает некоторые функции Java 5, но он может использовать перечисления (не определять) и скомпилировать "общий" (стирать), поэтому этого должно быть достаточно для того, что я хочу.
Я не хочу отмечать ответ как принятый, так как я надеюсь на лучшее решение.
Edit3: Принято предложение beanshell - оно действительно работает чудесно.
Ответы
Ответ 1
Если вы не полностью привязаны к компиляции, такие решения, как Beanshell, groovy и другие языки сценариев, легко внедряются (по сути, у java есть встроенная поддержка для подключения языка сценариев, поэтому ваш код не " t даже знаю, на каком языке написан script)
Beanshell должен запускать любой 100% -ный код Java IIRC, и я считаю, что groovy может запускать большинство java-кода - возможно, все.
Ответ 2
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
По какой причине это не должно работать?
Изменить: добавлен MemoryResourceStore
для отправки скомпилированного класса в память, как и запрошено.
Кроме того, установка javac
настроек, таких как classpath в вашем случае, может быть выполнена с помощью setCustomArguments(String[] pCustomArguments)
в классе JavacJavaCompilerSettings
.
Ответ 3
Возможно, вы захотите также проверить Янино.
На своем веб-сайте:
Janino - это компилятор, который считывает выражение JavaTM, блок, тело класса, исходный файл или набор исходных файлов и генерирует байт-код JavaTM, который загружается и выполняется напрямую. Janino не предназначен для разработки, но встроенный компилятор для целей компиляции во время выполнения, например. оценщики выражений или "серверные страницы", такие как JSP.
http://www.janino.net/
В настоящее время я использую его в довольно большом критически важном проекте, и он отлично работает
Ответ 4
Javassist может вас заинтересовать
Ответ 5
Запустите внутри веб-контейнера, такого как Tomcat, и сначала создайте страницу JSP, а затем вызовите его.
Это также позволяет избавиться от старых определений классов, просто перезаписав страницу JSP, вместо того, чтобы ваш загрузчик классов медленно работал полностью.
Является ли требование "в памяти" из-за скорости или из-за отсутствия изменения базы кода?
Ответ 6
ECJ Eclipse Java Compiler
Eclipse предоставляет и использует свой собственный компилятор, который не является javac
- Компилятор Eclipse используется внутри IDE (Eclipse)
- Компилятор Eclipse также может использоваться как чистый пакетный компилятор
вне Eclipse
Скомпилировать исходный файл
$ java -jar ecj-3.5.2.jar HelloWorld.java