Обработка аннотаций Java с манипулированием исходным кодом

Я искал решение для нижеприведенного требования -

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

Я посмотрел на API ниже -

  • javax.annotation.processing — обработка аннотаций.
  • javax.lang.model.* — языковая модель, используемая в обработке аннотаций и API дерева компилятора.
  • com.sun.source.* — API дерева компилятора.

Я думал о разработке этого следующим образом:

  1. Написать процессор аннотаций
  2. Сгенерируйте дерево компилятора
  3. Редактируйте дерево компилятора во время выполнения, не затрагивая исходный файл.
  4. Предоставить дерево компилятору

Compiler Tree API кажется многообещающим, когда он дает доступ к com.sun.source.tree.MethodTree.

Однако API дерева компилятора, по-видимому, доступен только для чтения. Я не могу понять, как выполнить шаги 3 и 4

Есть ли какой-либо API для этого, который я могу использовать для выполнения задачи?

ПРИМЕЧАНИЕ. Я ищу только технику манипулирования исходным кодом. Нет манипулирования байт-кодом во время выполнения / АОП

Среда: Java 6


person user1128134    schedule 12.02.2013    source источник
comment
Эта библиотека аннотаций изменяет исходный код, инициализируя значение строкового поля на основе комментария над ним. . Может быть, вы можете использовать это в качестве примера.   -  person Juan Mendes    schedule 21.02.2014


Ответы (3)


Стандартный API обработки аннотаций не поддерживает прямое изменение исходного кода. Однако некоторые эффекты изменения исходного кода могут быть достигнуты путем создания суперкласса или подкласса(ов) аннотированного типа. В записи блога ниже показан пример этой техники:

"Свойства через обработку аннотаций"

person Joe Darcy    schedule 18.02.2013

Вы можете сделать это как-то ниже, что позволит вам выполнить 3) и 4).

Пример взят из пример процессора аннотаций Java

@SupportedAnnotationTypes( "com.javacodegeeks.advanced.processor.Immutable" )
@SupportedSourceVersion( SourceVersion.RELEASE_7 )
public class SimpleAnnotationProcessor extends AbstractProcessor {
  @Override
  public boolean process(final Set< ? extends TypeElement > annotations, 
      final RoundEnvironment roundEnv) {

    for( final Element element: roundEnv.getElementsAnnotatedWith( Immutable.class ) ) {
      if( element instanceof TypeElement ) {
        final TypeElement typeElement = ( TypeElement )element;

        for( final Element eclosedElement: typeElement.getEnclosedElements() ) {
       if( eclosedElement instanceof VariableElement ) {
           final VariableElement variableElement = ( VariableElement )eclosedElement;

           if( !variableElement.getModifiers().contains( Modifier.FINAL ) ) {
             processingEnv.getMessager().printMessage( Diagnostic.Kind.ERROR,
               String.format( "Class '%s' is annotated as @Immutable, 
                 but field '%s' is not declared as final", 
                 typeElement.getSimpleName(), variableElement.getSimpleName()            
               ) 
             );                     
           }
         }
       }
    }

    // Claiming that annotations have been processed by this processor 
    return true;
  }
}

Другой способ — использование projectlombok со специальным обработчиком.

Пример встроенного обработчика из GitHub Project Lombok. Эта аннотация добавляет блок try catch

public class SneakyThrowsExample implements Runnable {
    @SneakyThrows(UnsupportedEncodingException.class)
    public String utf8ToString(byte[] bytes) {
        return new String(bytes, "UTF-8");
    }

    @SneakyThrows
    public void run() {
        throw new Throwable();
    }
}

Это обрабатывается для

public String utf8ToString(byte[] bytes) {
    try {
        return new String(bytes, "UTF-8");
    } catch (UnsupportedEncodingException e) {
        throw Lombok.sneakyThrow(e);
    }
}

public void run() {
    try {
        throw new Throwable();
    } catch (Throwable t) {
        throw Lombok.sneakyThrow(t);
    }
}

Вы можете найти код обработчика на том же сайте Github/lombok.

person bhantol    schedule 26.09.2014

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

person Sarel Botha    schedule 18.02.2013