My current understanding of annotation processor is that it refers to code that pre-parses a file looking for certain annotations, generating or changing other code based on that. It happens before the regular compilation phase of your project.
In gradle we typically use apt, kpt - and I've seen sometimes the use of
annotationProcessor - to indicate that some dependency will be needed at "annotation processing time".
If the understand above is right, how does
compileOnly differs from apt, kpt, etc?
As you've said, there are couple of annotation processing solutions in Gradle:<ol><li>annotationProcessor facilities for Android</li> <li>apt for pure Java and Groovy</li> <li>kapt for Kotlin</li> </ol>
and so on. You can even implement one yourself! All of them use separate
configuration for annotation processing.
Some of them, indeed, used to use
compile classpath for processing. But this is not <em>semantically</em> corrent, it is not a "Gradle way". You should not mix your compile <em>time</em> only dependencies with the artifacts, required for you app to <em>run</em>. One simple scenario I can think of is creating fat JARs: most probably you do not want to pack and ship the processors you've used because it makes no sense! There may be other scenarios as well.
What you can do, thanks to Gradle's flexibility, is create another classpath (
configuration) and use it only for annotation processing and then just forget about them. It is kind of semantics: you're telling Gradle (and other developers) that these dependencies are not required for you application to run. And this is the place where
compileOnly differs from
compileOnly dependencies are mandatory for you code to operate, but they are meant to be <em>provided</em> by the environment. Will it be your application server, or plugin host system, or even you'll add them to the classpath manually - they will just <em>exist</em> on you runtime so you should not pack them with your distributable. But they are required to for your code to run. Some examples of
compileOnly dependencies are Servlet API (your classes obviously extend and use them, but it will be provided by the server) or, if you're writing a Jenkins plugin, Jenkins core APIs (your plugin will be installed in a Jenkins where that core already exists). JDK itself is kind of
compileOnly too. Annotation processors, on the contrary, are not meant to be used at runtime at all. They won't exist on classpath and they are not needed to run your app: they already generated some code that was compiled later.
Other implication of "mixing" configuration is performance. Just let me quote Android's documentation:<blockquote>
In previous versions of the plugin, dependencies on the compile classpath were automatically added to the processor classpath. That is, you could add an annotation processor to the compile classpath and it would work as expected. However, this causes a significant impact to performance by adding a large number of unnecessary dependencies to the processor.</blockquote>