JavaCompiler с пользовательским ClassLoader и FileManager
Я хочу скомпилировать исходный код без наличия зависимостей на компьютере.
Пример: файл A.java:
import some.pkg.B;
public class A extends B {...}
У меня нет источника B, я хочу подключить либо JavaFileManager, либо собственный ClassLoader, чтобы получить соответствующие символы (пакет 'some.package' и класс B), а затем использовать имеющуюся у меня службу, которая получает источник строка.
Код компиляции: (inputFiles имеет A.java)
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
CustomClassLoader classLoader = new CustomClassLoader();
StandardJavaFileManager standardfileManager = compiler.getStandardFileManager(this, null, null);
JavaFileManager fileManager = new CustomFileManager(standardfileManager, output, classLoader);
CompilationTask task = compiler.getTask(null, fileManager, this, null, null, inputFiles);
boolean result = task.call();
Хуки на JavaFileManager (getFileForInput..) и на моем загрузчике классов (findClass, loadClass ..) не сработали при компиляции, и я получил сообщения об ошибках:
A.java:#: package some.pkg does not exist
A.java:#: cannot find symbol
symbol: class B
РЕДАКТИРОВАТЬ
После игры с API, просмотра исходного кода JavaCompiler (более старой версии) и чтения обзора компиляции я все еще не могу найти хук API, который я могу использовать, чтобы предоставить мне символы из деревьев синтаксиса. Похоже, что API нужно получить все ресурсы на основе имен пакетов, как предлагает kschneid.
Один из обходных путей, о котором я подумал, - это запуск JavaCompiler и анализ сообщений об ошибках на наличие пропущенных символов. Таким образом я узнаю, какие символы нужны, получу их и перекомпилирую.
Любые другие обходные пути / решения?
2 ответа
(Я предполагаю, что вы на самом деле не используете имя пакета "package", так как это было бы просто незаконно...)
Ваш обычай JavaFileManager
должен получать его list
метод вызван. Надеюсь, эта запись имеет смысл, но комбинация аргументов этого метода должна выглядеть так:
[PLATFORM_CLASS_PATH, some, [CLASS], false]
[CLASS_PATH, some, [SOURCE, CLASS], false]
[PLATFORM_CLASS_PATH, some.pkg, [CLASS], false]
[CLASS_PATH, some.pkg, [SOURCE, CLASS], false]
Я не уверен, насколько сложно для вашей конкретной среды создать соответствующую Iterable<JavaFileObject>
случаи, но я думаю, что это то, что потребуется...
Я обнаружил, что хороший способ подключить классы во время компиляции - это Groovy AST Transformation. Вы можете посмотреть, что можно сделать здесь
Это не простая старая Java, но это может быть удобным инструментом, чтобы знать,