Processing Java annotations using source manipulation

I was looking for a solution for the below requirement -

  • Source files are written using custom annotation using the method
  • The body of the method needs a little change based on annotation.
  • The source file should not be changed, but the input to the compiler must be changed by the source file

I looked below the API -

  • javax.annotation.processing - Processing annotations.
  • javax.lang.model. * - The language model used in processing annotations and the compiler tree API.
  • com.sun.source. * - API of the compiler tree.

I thought about how to do this:

  • Write Annotation Handler
  • Generate compiler tree
  • Edit compiler tree at runtime without affecting the original source file
  • Put a tree in the compiler

The compiler API looks promising when it gives access to com.sun.source.tree.MethodTree

However, the compiler API is read-only. I can't figure out how to follow steps 3 and 4

Is there any API for this that I can accept to complete the task

NOTE. I am only looking for a source code manipulation method. No code byte manipulation at runtime / AOP

Environment: Java 6

+7
source share
3 answers

You can do this as something below, which allows you to fulfill 3) and 4).

Example from java annotation processor example

@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; } } 

Another way to use projectlombok with a custom handler.

An example of a built-in handler from the GitHub Project Lombok. This annotation adds a catch catch block.

 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(); } } 

It is being processed

 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); } } 

You can find the handler code on the same Github / lombok site.

+3
source

The standard annotation processing API does not support direct modification of the source code. However, some effects of changing the source code can be obtained by creating either a superclass or a subclass of the annotated type. The blog entry below shows an example of this technique:

"Properties using annotation processing"

+2
source

I would advise you to copy the entire source code into a separate directory, change the code there and build from a temporary path.

0
source

All Articles