Как получить все элементы с аннотацией в инкрементальной сборке IntelliJ? - PullRequest
2 голосов
/ 14 мая 2019

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

Чтобы немного упростить, приведем следующие исходные файлы:

src / main / java / org / example / A.java
@Annotation
class A {}
src / main / java / org / example / B.java
@Annotation
class B {}

Я хочу создать класс:

target /generate-sources / org / example / Module.java
class Module {
  String getModuleClasses() {
    return Arrays.asList(
      "org.example.A",
      "org.example.B"
    );
  }
}

Это работает от Maven, но когда я изменяю класс A, IntelliJ дает моему процессору аннотаций RoundEnvironment с A в качестве единственного корневого элемента.

Я понимаю, что Gradle поддерживает инкрементную компиляцию с агрегирующими процессорами аннотаций путем передачи фальшивого RoundEnvironment со всеми источниками, соответствующими аннотациям к процессору аннотаций, но IntelliJ, похоже, ничего не имеетаналогичный.(За исключением, может быть, для проектов Gradle?)

Как лучше всего найти оба класса, когда IntelliJ компилирует только класс A?

Возможно, аннотатор мог бы хранить список аннотированных классов: читать список из файла ресурсов в первом раунде, в каждом раунде удалять из списка корневые элементы и добавлять в список аннотированные элементы списка и писатьсписок обратно в файл ресурсов в последнем раунде?

1 Ответ

3 голосов
/ 15 мая 2019

Одним из способов решения этой проблемы является использование какого-либо реестра между сборками, например, вы можете хранить типы, аннотированные в стиле, подобном сервису, в meta-inf

Таким образом, в вашем процессоре вы откладываетегенерация кода до последнего раунда обработки, и после генерации вашего кода вы сохраняете типы в файле в файл под META-INF

FileObject resource = processingEnv.getFiler()
                    .createResource(StandardLocation.CLASS_OUTPUT, "", "META-INF/annotatedtypes/"+fileName);
PrintWriter out = new PrintWriter(new OutputStreamWriter(resource.openOutputStream()));
            classes.forEach(out::println);

. Вы должны проверить наличие дублирующихся записей, конечно.

В какой-то момент перед генерацией кода прочитайте типы и сгенерируйте ваш код на основе этого

FileObject resource = processingEnv.getFiler()
                        .getResource(StandardLocation.CLASS_OUTPUT, "", "META-INF/annotatedtypes/"+fileName);
new BufferedReader(new InputStreamReader(resource.openInputStream())).lines().forEach(classes::add);

содержимое файла может выглядеть примерно так

org.foo.bar.A
org.foo.bar.B

Проблемаэто означает, что когда вы откладываете генерацию кода до последнего раунда, ваш сгенерированный код не будет выбран любым другим процессором, например dagger2, а также иногда файл может заканчиваться записями для классов, которых больше не существует.

В итоге внутри вашего процессора вы делаете следующее

  • Чтение зарегистрированных типов из файлав META-INF
  • Получить элементы, аннотированные вашей аннотацией.
  • Если это последний раунд, просто обновите файл с уникальным набором записей и сгенерируйте код.

Вы читаете файл каждый раунд, но пишете только один раз в последнем раунде.

...