Java 6 - Обработка аннотаций и добавление кода

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

@SupportedAnnotationTypes({"<package>.Property"})
public class PropertyProcessor extends AbstractProcessor {

    @Override
    public boolean process(Set<? extends TypeElement> annotations,
            RoundEnvironment roundEnv) {
        // Get messager object
        Messager messager = processingEnv.getMessager();
        // Iterate through the annotations
        for(TypeElement typeElement : annotations) {
            // Iterate through the annotated elements
            for(Element element : roundEnv.getElementsAnnotatedWith(typeElement)) {
                // Get Property annotation
                Property property = element.getAnnotation(Property.class);

            }
        }
        return false;
    }

}

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

Ответы

Ответ 1

Вы пробовали Google Guice?

Google Guice позволяет вам немного ориентировать по аспектам программирования, перехватывая методы. Если это все, что вам нужно сделать, вы можете реализовать MethodInterceptor, который позволит вам переопределять методы во время выполнения. Он действительно опрятен для изоляции сквозных проблем.

Например, можно сказать, что вы хотите запретить выполнение определенных методов в выходные дни, вы можете их аннотировать так:

@Property
public class SomeClass {
    public Receipt doSometing() {
        // Do something
    }
}

Определить методInterceptor:

public class PropertyInterceptor implements MethodInterceptor {
  public Object invoke(MethodInvocation invocation) throws Throwable {
    // For example prevent the classes annotated with @Property
    // from being called on weekends
    Calendar today = new GregorianCalendar();
    if (today.getDisplayName(DAY_OF_WEEK, LONG, ENGLISH).startsWith("S")) {
      throw new IllegalStateException(
          invocation.getMethod().getName() + " not allowed on weekends!");
    }
    return invocation.proceed();
  }
}

И затем привяжите перехватчик к аннотации:

public class PropertyModule extends AbstractModule {
  protected void configure() {
        PropertyInterceptor propertyInterceptor = new PropertyInterceptor();        
        bindInterceptor(Matchers.annotatedWith(Property.class), 
        Matchers.any(), propertyInterceptor);
  }
}

Ответ 2

Короткий ответ: вы не должны изменять исходный код во время обработки аннотаций.

Недавно у меня была ситуация, когда этот ответ был неудовлетворительным (см. этот вопрос). Мои решения заключались в том, чтобы программно добавить код, который мне нужен, используя внутренний javac api. Подробнее см. мой ответ на мой вопрос.

Я вдохнул это из Project Lombok, начиная с исходного кода и отбрасывая все, что мне не нужно. Я не думаю, что вы найдете намного лучшую отправную точку.

Кстати, Javassist, вероятно, не поможет, потому что вы имеете дело с исходным деревом, а не с байтовым кодом. Если вы хотите использовать библиотеку управления байтовым кодом, вы можете сделать это либо статически после компиляции, либо динамически при загрузке классов, но не во время обработки аннотаций, поскольку это шаг предварительной компиляции.

Ответ 3

Обработка аннотаций не предназначена для изменения существующих классов - это просто для генерации дополнительного кода/ресурсов (по принципу "один за другим", иначе вы столкнетесь с трудностями при повторной компиляции только измененных источников).

Некоторое время назад я попробовал Spoon для аналогичной проблемы: мне очень понравилась идея программного процессора (и IDE интеграция еще больше), но в то время это было не очень стабильно...

В зависимости от вашего прецедента инструмент AOP (например: AspectJ) может выбрать вас лучше, чем Spoon, и, конечно же, - вы всегда можете использовать генератор исходного кода или реализовать полномасштабную DSL (посмотрите на фантастический Xtext).

В зависимости от размера, оборота и "интеллектуальной инерции" ваших товарищей по команде вы могли бы лучше переносить ботинки простой java вместо того, чтобы вводить новый инструмент/технологию, формировать коллег и интегрировать новые инструмент в вашей системе CI. Внимательно взвешивайте затраты/выгоды.