Java 6 - процессор аннотаций и добавление кода - PullRequest
15 голосов
/ 18 сентября 2010

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

Ответы [ 3 ]

6 голосов
/ 21 сентября 2010

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

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

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

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

Определите MethodInterceptor:

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);
  }
}
5 голосов
/ 20 сентября 2010

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

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

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

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

1 голос
/ 22 сентября 2010

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

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

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

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

...