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 и анализ сообщений об ошибках для отсутствующих символов. Таким образом, я буду знать, какие символы необходимы, получить их и перекомпилировать.
Любые другие обходные пути/решения?

Ответ 1

(Я предполагаю, что вы действительно не используете имя пакета "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>, но я думаю, что потребуется...

Ответ 2

Я обнаружил, что хороший способ подключиться к классам во время компиляции - Groovy AST Transformation. Вы можете посмотреть, что можно сделать здесь

Это не простая старая java, но она может быть удобным инструментом, чтобы знать