Direct communication between Java annotation processors and Gradle scripts

Firstly, I would like to say that I have been very pleased with how well Gradle has worked with our build process (I’m a programmer with Penn State University working on porting our builds over from Ant to Gradle).

But I have come across a problem and I think I have a solution.

My team leader had the idea of using annotations on classes and packages in order to mark them for which client jars they should be put into.

I originally thought that all I would have to do was add a static member with the necessary data to the annotation processor’s class and access that data directory from a Gradle script. e.g.:

import proc.MyAnnoProc
  // declare compilation and script dependencies on annotation and processor jars
  task doSomethingWithAnnotationData(dependsOn: compileJava) {
    doSomethingWith(MyAnnoProc.getDataFromProcessing())
}

But this does not work, because the annotation processor class used by the Java compiler is loaded by a different classloader than the one used by the Gradle script. So we have two different versions of the annotation processor class that we want.

I’ve made a proof-of-concept that allows me to pass information directly between annotation processor classes and Gradle scripts in the manner that I’ve described above.

This is the first time I’ve ever made a useful (I think) modification to an open-source project so I am completely new to this.

Any feedback, questions, and/or information telling me that this-is-already-available-in-Gradle-why-didn’t-you-read-the-docs-etc is welcome. :slight_smile:

Hi Alexander,

The classloaders are isolated by design, and moreover we are moving towards out of process compilation. It turns out that compiling in process is too risky as it can pollute the build JVM.

Is the issue just that you need to split up one source set into multiple jars? Or is it something else?

Hi Luke, thank you for responding!

Currently what we are doing is using a separate file that lists all the classes and packages and the jar that they must go to. This is error prone as developers forget to modify this file whenever they remove/add a class/package, which you can imagine causes headaches for everyone.

My idea was to have an annotation processor class that could inform Gradle of what classes and packages are marked with an annotation that says what jar the class/package goes to. It would be very convenient for our developers to just annotate a class or package, that way it would be clear when looking at the source code what jar a class goes to. I can imagine such a system could be expanded to allow a Gradle script to respond in different ways depending on what annotations are used (what tests to run, outside dependencies used by a class, abort on too many deprecated methods/classes, etc.). All that would be necessary would be for the JavaCompiler class to be able to selectively access the same classes loaded by the Gradle script classloader. A MutableURLClassLoader if I’m not mistaken.

I tested to see what would happen if that were possible and it does work, though the method is crude considering I’m working around the classloader system that Gradle is currently using.

If Gradle is moving to out of process compilation then my idea would be quite impractical, but it would be a neat feature if it could be implemented.

This kind of thing is usually done by inspecting the class files that are the result of the compilation.