Статическое метапрограммирование Java - PullRequest
4 голосов
/ 05 декабря 2011

Я хотел бы реализовать процессор аннотаций, который будет генерировать новый класс на основе существующего класса «прототип».

import java.util.List

@MyAnnotation
class MySuperClassPrototype {
    static MySuperClassPrototype createInstance() {
      return new MySuperClassPrototype();
    }
}

В результате кода ниже. Будет создан следующий новый исходный файл (модуль компиляции):

import java.util.List

class MySuperClass {
    static MySuperClass createInstance() {
      return new MySuperClass();
    }
    public void specialAddedMethod() {
      /*...*/
    }
}

Я хотел бы скопировать все операторы импорта верхнего уровня и статические члены, а не статические члены класса prototype. Я продвинулся довольно далеко с API дерева компиляторов (com.sun.source.tree). Я могу распечатать тип данных Tree при замене нового имени класса на старое. Но есть проблемы, которые кажутся довольно сложными.

Если я получаю Tree.Kind.IDENTIFIER в дереве, как я могу найти, на какой реальный класс он ссылается. Мне нужно заменить все вхождения идентификатора MySuperClassPrototype на идентификатор MySuperClass, а затем распечатать все дерево.

Возможно ли это?

Аналогичным образом мне нужно отфильтровать аннотацию @MyAnnotation, и она снова будет представлена ​​с помощью Tree.Kind.IDENTIFIER или Tree.Kind.MEMBER_SELECT.

Как узнать фактический класс аннотаций, на который ссылается этот идентификатор?

И еще одна проблема - распечатка дерева. Если я использую метод toString, я получаю приличный результат, но конструкторы печатаются как методы с именем "" вместо методов с тем же именем, что и его класс, поэтому мне нужно вручную печатать каждый тип узла дерева.

Вы можете увидеть код, с которым я пришел сюда

Ответы [ 2 ]

6 голосов
/ 05 декабря 2011

Да, это возможно, и я знаю как минимум 2 способа.

Во-первых, «традиционный» способ - написать утилиту ant task / maven plugin / just для командной строки, которая сканирует заданный путь к файлу и вызывает для каждого класса что-то вроде Class.forName(className).getAnnotations(MyAnnotation.class).Если это не ноль, откройте класс, используя рефлексию, и делайте то, что вам нужно.

Другой способ немного сложнее, но мощнее.Вы можете реализовать свой собственный Processor (который реализует javax.annotation.processing.Processor или, что еще лучше, расширяет javax.annotation.processing.AbstractProcessor. Ваш процессор просто нужно будет поместить в путь к классу compiler, и он будет работать автоматически при запуске компилятора. Вы даже можете настроить свойIDE (например, Eclipse) для запуска вашего процессора. Это своего рода расширение для компилятора java. Поэтому каждый раз, когда eclipse строит ваш проект, он запускает процессор и создает все новые классы в соответствии с добавленными вами новыми аннотациями.

Пожалуйста, ознакомьтесь с этим проектом в качестве справочного материала.

0 голосов
/ 28 апреля 2017

взгляните на https://github.com/rzwitserloot/lombok/, Это добавляет методы, как вы описали.например,

  • @ Getter add методы получения на основе полей
  • @ Setter
  • @ ToString add toString() методы на основе полей
...