Оперативная компиляция Java-кода в памяти для Java 5 и Java 6 - PullRequest
17 голосов
/ 05 марта 2009

Как я могу скомпилировать код Java из произвольной строки (в памяти) в Java 5 и Java 6, загрузить его и запустить на нем определенный метод (предопределенный)?

Перед тем, как вы раскритиковали это, я просмотрел существующие реализации:

  • Большинство полагается на Java 6 Compiler API.
  • Те, кто этого не делают, полагаются на уловки.
  • Да, я проверил commons-jci. Либо я слишком дремучий, чтобы понять, как это работает, либо нет.
  • Я не мог найти, как передать компилятору мой текущий путь к классу (который довольно большой).
  • В работающей реализации (в Java 6) я не смог найти, как правильно загружать внутренние классы (или внутренние анонимные классы).
  • Мне бы очень хотелось, чтобы все это было в памяти, поскольку оно работает в нескольких средах.

Я уверен, что это было решено раньше, но я не могу найти ничего, что выглядит даже наполовину качественно в Google (кроме jci, который, как я уже говорил, мне не удалось использовать) .

Редактировать:

  • Я просмотрел JavaAssist - мне нужны внутренние классы, поддержка уровня языка Java 5.0 и компиляция со всем путем к классам. Кроме того, я хотел бы создавать новые классы на лету. я возможно, ошибаюсь, но я не смог найти, как это сделать с помощью JavaAssit.
  • Я готов использовать решение на основе файловой системы (вызывающее javac), но я не знаю, как угадать путь к классам или как впоследствии загрузить файлы (которых нет в моем классе) с помощью специального загрузчика классов которые могут быть переработаны для нескольких вызовов. Хотя я знаю, как его исследовать, я бы предпочел готовое решение.

Edit2: На данный момент я доволен BeanShell "оценить". По-видимому, он делает все, что мне нужно (получить строку, оценить ее в контексте «текущего» пути к классам. Он пропускает некоторые функции Java 5, но может использовать перечисления (не определить) и скомпилированные «общие» (стерты) ) классов, так что должно быть достаточно для того, что я хочу.

Я не хочу помечать ответ как принятый, поскольку надеюсь найти лучшее решение.

Edit3: принял предложение бобовой скорлупы - оно действительно прекрасно работает.

Ответы [ 6 ]

9 голосов
/ 05 марта 2009

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 class.

6 голосов
/ 06 марта 2009

Возможно, вы захотите проверить и Янино.

С их сайта:

Janino - это компилятор, который читает выражение JavaTM, блок, тело класса, исходный файл или набор исходных файлов и генерирует байт-код JavaTM, который загружается и выполняется напрямую. Janino не предназначен для разработки, но является встроенным компилятором для целей компиляции во время выполнения, например средства оценки выражений или «серверные страницы», такие как JSP.

http://www.janino.net/

В настоящее время я использую его в довольно большом критически важном проекте, и он прекрасно работает

3 голосов
/ 06 марта 2009

Если вы не полностью привязаны к компиляции, такие решения, как Beanshell, groovy и другие языки сценариев, легко встраиваются (фактически, в Java есть встроенная поддержка для подключения языка сценариев, поэтому ваш код даже не будет знать, на каком языке написан скрипт)

Beanshell должен запускать любой 100% -ный Java-код IIRC, и я считаю, что Groovy может выполнять большую часть Java-кода - возможно, все.

1 голос
/ 05 марта 2009

Javassist может вас заинтересовать

0 голосов
/ 13 декабря 2013

Компилятор ECJ Eclipse Java

Eclipse предоставляет и использует свой собственный компилятор, который не является javac

  • Компилятор Eclipse используется внутри IDE (Eclipse)
  • Компилятор Eclipse также можно использовать как чистый пакетный компилятор вне затмения

Скомпилируйте исходный файл

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

0 голосов
/ 06 марта 2009

Запустите внутри веб-контейнера, такого как Tomcat, сначала создайте страницу JSP, а затем вызовите ее.

Это также позволяет вам избавиться от старых определений классов, просто переписав страницу JSP вместо того, чтобы ваш загрузчик классов медленно заполнялся.

Является ли требование "в памяти" из-за скорости или из-за отсутствия изменения базы кода?

...