Обработка на Java анотация с манипулиране на изходния код

Търсих решение за по-долу изискване -

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

Разгледах API по-долу -

  • javax.annotation.processing - Обработка на анотация.
  • javax.lang.model.* - Езиков модел, използван при обработката на анотации и API на Compiler Tree
  • com.sun.source.* - API на дървото на компилатора.

Мислех да проектирам това, като следвам:

  1. Напишете процесор за обработка на анотации
  2. Генерирайте дървото на компилатора
  3. Редактирайте дървото на компилатора по време на изпълнение, без да засягате оригиналния изходен файл
  4. Доставяне на дървото на компилатора

API на Compiler Tree изглежда обещаващ, когато дава достъп до com.sun.source.tree.MethodTree

Въпреки това изглежда, че API на дървото на компилатора е само за четене. Не мога да разбера как да изпълня стъпки 3 и 4

Има ли някакъв API за това, който мога да приема, за да изпълня задачата

ЗАБЕЛЕЖКА: Търся само техника за манипулиране на изходния код. Без манипулиране на байт код по време на изпълнение / AOP

Околна среда: 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);
    }
}

Можете да намерите кода на Handler на същия сайт на Github/lombok.

person bhantol    schedule 26.09.2014

Предлагам ви да копирате целия изходен код в отделна директория, да промените кода там и да изградите от временния път.

person Sarel Botha    schedule 18.02.2013