Хорошо, чтобы прояснить вашу проблему, я переформулирую вопрос.
Как собрать все пути классов для всех задач в файле build.xml, даже если некоторые из них могут быть вложены в определения ?
Простой ответ заключается в том, что общий ответ для каждого случая невозможен. Причины этого глубоко связаны с теорией информатики, охватывающей вопросы вычислимости и ограничения машины Тьюринга. В вашем случае мы знаем, что входные данные могут быть бесконечными (поскольку язык ANT может ссылаться на временные метки), и что выходные данные могут быть отражением входных данных, поэтому мы знаем , что потребуется бесконечное количество времени для сбора каждого возможного пути к классам.
Тем не менее, шансы превосходны, что вы можете легко вывести некоторые пути к классам и даже, возможно, вывести все пути к классам за разумное (т. Е. Бесконечное) количество времени. Ключевым моментом является то, что ANT выполняет множество предварительных настроек, но в конечном итоге необходимо выполнить некоторые настройки на лету. classpath в цели настроен заранее; потому что решение ANT сделать все переменные неизменяемыми. Это означает, что для «типичного» тега javac вам нужен только код, который выглядит следующим образом:
if (task instanceof Javac) {
Javac javac = (Javac)task;
Path path = javac.getClasspath();
if (path == null) {
System.out.println("javac: Path is null");
} else {
System.out.println("javac: Path is " + path.toString());
}
}
Но вложенному в тег javac macrodef потребуется симуляция прогона. Фактическая конфигурация не будет храниться непосредственно внутри задачи, она будет храниться в оболочке RuntimeConfigurable
вокруг класса. Узлы Task
будут создаваться при выполнении проекта, что означает, что их конфигурация будет вычислена на лету.
Я перечислю немного кода о том, как перейти к дочерним элементам macrodef Wrapper:
if (task instanceof MacroDef) {
MacroDef macroDef = (MacroDef)task;
// a Sequence element, but not really, as `unkSeq.getRealThing()` will return null
UnknownElement unkSeq = macroDef.getNestedTask();
// Make sure we are dealing with the wrapper, or we won't get very far
RuntimeConfigurable wrapper = unkSeq.getWrapper();
// Wrappers can be configured too.
wrapper.maybeConfigure(project, true);
Enumeration enumeration = wrapper.getChildren();
while (enumeration.hasMoreElements()) {
// children of the wrapper
RuntimeConfigurable child = (RuntimeConfigurable) enumeration.nextElement();
UnknownElement unkchild = (UnknownElement)child.getProxy();
// you can use this to print the name
System.out.println("child(wrapper): " + unkchild.getTaskName());
// this will be null, as the macro hasn't "executed"
System.out.println("child(real): " + unkchild.getRealThing());
}
}
Поскольку фактически вызываемая задача javac
не существует в предопределении макроса, невозможно по-настоящему «знать» ее путь к классу во всех случаях до выполнения. Да, вы можете сделать какой-нибудь модный код для имитации прогона, отслеживая переходные свойства ANT, но вы никогда не сможете «доказать», что такой код совпадает с прогоном, если вы не имеете дело с подмножеством свойств (а именно с теми, которые гарантированы всегда имеют одинаковое значение между все прогонов).
Надеюсь, я не пропустил оценку, ответив на ваш вопрос, и, если я так и сделал, надеюсь, что что-то из этого будет полезным для вашего решения вашей проблемы. Будьте уверены, что существует нет решения для распечатки пути к классам для каждого возможного файла build.xml, где задачи javac встроены в вызовы macrodef.
--- оригинальный пост следует ---
Чтобы действительно захватить содержимое макроопределения, вам нужно захватить задачу, которая ссылается на макроопределение, а затем захватить макроопределение, а затем посмотреть на элементы внутри макроопределения (помня, что они тоже могут быть макросами).