Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I use compileOnly as a replacement for annotationProcessor in gradle?

Tags:

gradle

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?

like image 250
Humble Student Avatar asked Jan 03 '23 05:01

Humble Student


1 Answers

As you've said, there are couple of annotation processing solutions in Gradle:

  1. annotationProcessor facilities for Android
  2. apt for pure Java and Groovy
  3. kapt for Kotlin

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 semantically corrent, it is not a "Gradle way". You should not mix your compile time only dependencies with the artifacts, required for you app to run. 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 apt: compileOnly dependencies are mandatory for you code to operate, but they are meant to be provided 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 exist 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:

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.

like image 125
madhead - StandWithUkraine Avatar answered Jan 05 '23 20:01

madhead - StandWithUkraine