27

I may be just looking in the wrong direction but I find the JSE documentation on annotation processing very ... sparse. I want to write an annotation processor which processes annotated String fields and local variables to substitute them with a computed String expression. This should not be too complicated but I'm pretty lost in the Javadoc for javax.annotation.processing.

EDIT: I need to process annotations at compile time because I want to modify the generated code. It should replace annotated constant String expressions with a computed String expression.

Christian Schlichtherle
  • 3,125
  • 1
  • 23
  • 47
  • Agreed, my entry point was this tutorial: http://tutorials.jenkov.com/java-reflection/annotations.html – Konrad Reiche Jul 08 '12 at 18:39
  • 2
    Do you want to process annotations at compile time or runtime? Note that annotations on local variables are effectively useless due to a silly javac limitation. – Paul Bellora Jul 08 '12 at 18:43
  • I want to process them at compile time, so this would obviously only work for constant string expressions. – Christian Schlichtherle Jul 08 '12 at 19:03
  • You might be able to use ANT's [replace task](http://ant.apache.org/manual/Tasks/replace.html), but that might depend on what "computed" means. See [this post](http://stackoverflow.com/questions/8433588/retrieve-value-from-text-file-and-replace-a-string-constant-in-another-file-with) for example. – Paul Bellora Jul 08 '12 at 23:33
  • Maybe it will be useful: https://github.com/vbauer/jackdaw – Vladislav Bauer Mar 22 '15 at 14:19
  • https://github.com/adrianwalker/multiline-string/blob/984ba3cc69e2a1b5a73b8d9dc092ae0adcbb863e/multiline-string/src/main/java/org/adrianwalker/multilinestring/MultilineProcessor.java#L39 sounds remotely similar to what you'd like to do and is a rather easily overlookable example. – Caesar Feb 14 '20 at 06:44

3 Answers3

15

This can not be done with a compile time annotation processor. Compile time time annotation processors can only generate new files (and classes) they can not modify existing classes. You can do reflection at runtime but strictly speaking you that is not called annotation processing. Also you won't have access to local variables.

If you're looking on how to write a compile time annotation processor check out https://github.com/pellaton/spring-configuration-validation-processor

Graham Borland
  • 60,055
  • 21
  • 138
  • 179
Philippe Marschall
  • 4,452
  • 1
  • 34
  • 52
  • Theoretically, you could use an annotation processor + Apache BCEL (or something similar) to modify the original .class file. But that sounds messy. – vanza Jul 08 '12 at 18:53
  • Err... what? I cannot modify the source code before compilation using the annotation framework? – Christian Schlichtherle Jul 08 '12 at 19:11
  • 1
    I looked at the linked code. Obviously it doesn't generate code, it just validates it. I was hoping I could modify the Abstract Syntax Tree before the actual code generation step. – Christian Schlichtherle Jul 08 '12 at 19:28
  • 1
    I think your only options are bytecode manipulation (using e.g. ASM, BCEL) or some classpath tricks like reference to the class that is generated by the annotation processor instead to the original file or something like that... – s106mo Jul 08 '12 at 20:30
  • @Christian Yea, you can do byte code fun, but not generate new code. Now, you can write an annotation processor that DOES generate new code, but that would not be part of the "compile" process. It would be like javadoc, creating "new files" that could then be compiled. A 2 stage process. – Will Hartung Jul 08 '12 at 22:22
  • 1
    @christian-schlichtherle Yes, you can't modify. Check out the [apt documentation](http://docs.oracle.com/javase/6/docs/technotes/guides/apt/index.html). "These reflective APIs provide a build-time, source-based, **read-only** view of program structure." "runs annotation processors that can produce **new source code and other files**" – Philippe Marschall Jul 09 '12 at 07:32
8

Two tools that do this are Project Lombok and DuctileJ. Both of these tools existed at the time the question was originally asked; additional tools now surely exist.

The key idea is to write an annotation processor that traverses and modifies the program's AST (abstract syntax tree) during compilation, before code generation. The compiler won't change the source code on disk, but the generated .class file will reflect the changes that your annotation processor makes.

You may be able to adapt one of these tools to suit your needs, or you could implement your own tool inspired by their implementation techniques.

Compile-time processing has two advantages over class-file processing. One is that the compiler usually has more information than is available from compiled code. Another is that everything happens in one step, during compilation, rather than requiring the developer to run a separate tool to rewrite the .class files after compilation.

rob
  • 36,896
  • 2
  • 55
  • 65
mernst
  • 7,437
  • 30
  • 45
  • 2
    sure, and worth mentioning that both use a hack to modify the AST, exploiting a bug in the current annotation processor in Java, making use of internal javac APIs which could be fixed/removed in some future JDK (which goes down as a big disadvantage to me). – Neil Stockton Nov 11 '15 at 16:58
  • I'm sorry, but as helpful this answer might be, its statements simply are not true. The mentioned tools are not aspect processors, but compiler plugins (completely different method, not as well supported in some tools). You cannot modify AST with aspect processor -- only generate new code in new compilation units (e.g. new classes) – pwes Dec 06 '22 at 10:27
4

Check

Ondra Žižka
  • 43,948
  • 41
  • 217
  • 277
  • I have looked at Javassist and ASM. Maybe they would do the job, but they are about byte code manipulation. I would very much prefer to use a tool which would allow me to manipulate the Abstract Syntax Tree. Byte code manipulation would only be my last resort. – Christian Schlichtherle Jul 08 '12 at 22:41
  • OK, after investigating the options, it seems that byte code manipulation is the only viable option left. The next challenge is to integrate this into a Maven build - not just for me, but for the users of my library, too. – Christian Schlichtherle Jul 09 '12 at 12:53