IntroductionFirst things first, a definition. An annotation processor is a library that can be added to the javac compiler and that can enhance our source code if the right annotations are used. It allors us to write more concise and mode expressive code.
Note that "enhancing source code" needs to be clarified, as JSR-269 does not allow modifications of existing .java files. However, it is possible to create new .java files, just like AndroidAnnotations does, or to modify generated bytecode, like project lombok does (with a little bit of hacking, though).
A great variety of IDE (Eclipse, NetBeans, IntelliJ) supports annotation processors, whether using or developing it. But there is a lack of documentation on debugging such tools. For instance, very few pages references debugging an annotation processor in Eclipse, and all mention the creation of a plugin.
During the HackerGarten, we chose a different method : since annotation processors are a java library that is added to javac, we "only" have to launch javac in debug mode, and connect to it. In this article, we will focus on IntelliJ but the solution will work for any IDE.
Adding the annotation processor to the compilerOnce the project is imported in Intellij, we can add the annotation processor to the compilation process. Do to so, we have to enter the fully-qualified name of AndroidAnnotations processor, the module on which we want to process the annotations and an output folder. There are lots of test classes in the module
functionnal-test-1-5, let's use this one and specify the output directory
Checking that annotations are processedWhen we process the class
BeanInjectedActivity.java, we can see that a new java source file named
BeanInjectedActivity_.javais created in the folder
target/processed. This new file contains the code of the original class and many more statements that have been added by the annotation processor.
Setting javac in debug modeWe know that any JVM instance can be started in debug mode using some JVM Options, such as
-Xdebug. Unfortunately, in our case, we have to use the
javaccommand which is not itself a JVM instance, so it is not possible to pass it such options.
However, javac *creates* a JVM instance in which the compilation process takes place. We can send JVM options to this instance using the command line parameter
-J, as stated in the manpage :.
-J option Pass option to the java launcher called by javac. For example, -J-Xms48m sets the startup memory to 48 megabytes. It is a common convention for -J to pass options to the underlying VM executing applications written in Java.
We can therefore use the options
-J-Xdebug -J-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005to run the compilation JVM in debug mode. Let's add those options in IntelliJ and set a breakpoint in the
Adding a debugging configuration and debuggingWe can now add a remote debugging configuration on port 5005 in IntelliJ and process the class
BeanInjectedActivity.java. We see that the compilation process hangs on "make", which is as expected since the compiler is now waiting a connection from a debugger. When we start the remote debugging configuration in IntelliJ, we see that :
- the compiler stops at the breakpoint we added in
- the stacktrace mentions the javac compiler itself.
ConclusionWe saw that the javac compiler itself could be run in debug mode and therefore, any annotation processor can be debugged using any IDE that supports setting additional javac arguments.
Do you have other techniques do debug annotation processors ? A particular opinion about them ? Let's talk about it in the comments !