What is the best way to react to a plugin configuration

For example, if I want to react to the java plugin, e.g. I’d like to modify the destination dir of the compile task and insert a step task that will output the classes in the original compile task output.
All with configuration avoidance.

Is the following OK ? Assuming there is code that apply the java plugin before.

project.extensions.getByType(JavaPluginExtension.class).getSourceSets().configureEach(sourceSet -> { })

Or maybe

project.getExtensions().configure(SourceSetContainer.class, sourceSets -> sourceSets.configureEach(sourceSet -> { })

Thinking about it, I want to post-process the classes before they land in the usual build/classes.


Also I suppose this would be ok to modify there the output dir of the compile task. E.g. replacing the destinationDirectory (and keeping it under the hood for a a new task to be registered)

Maybe something like this instead ? But, if the post-processing changes for some reason but not the classes themselves. This will require to recompile everything in the module ?

javaPluginExtension.sourceSets.all { sourceSet ->
  project.tasks.named(sourceSet.getCompileTaskName(language), AbstractCompile) {
    it.inputs // add anything that need to be tracked.
    it.doLast("postProcessor") {
      // my post processing
    }
  }
}

Actually unsure about the best approach to swap the task output.

FileCollection classesDirs = sourceSet.output.classesDirs

Provider<Directory> rawClassesOutputDir = project.layout.buildDirectory.dir("rawClasses/${sourceSet.name}")

project.tasks.named(compileTaskName, AbstractCompile) { AbstractCompile compilerTask ->
  compilerTask.destinationDirectory.set(rawClassesOutputDir)
}

project.tasks.register(compileTaskName.replace('compile', 'postProcess')) {
  it.inputs.dir(rawClassesOutputDir)  // new output from the compile task
  it.outputs.dir(sourceSet.output)

  it.destinationDirectory.set(...) // TODO ...
}

classesDir is a FileCollection, but in the post process task I’d like a DirectoryProperty (for destinationDirectory)

Is the following OK ? Assuming there is code that apply the java plugin before.

Yes, if you apply the plugin before, then it is safe and normal to access the extension the plugin created, configure the tasks the plugin registered, and so on.
Both lines should be fine I think.

Thinking about it, I want to post-process the classes before they land in the usual build/classes.

Sounds like you want to do some instrumentation of the class files.
Usually the best way is to not reconfigure task output directories and insert a new task, but instead to add a doLast action to the compile task that does the post-processing. Be aware that it should cope with the task being incremental, meaning it does not necessarily compile all files, so you should only instrument what was

If someone for example directly uses the compile task output they would otherwise not get the instrumented ones.
Besides that, in Gradle 9 if you change the compile task destination directory, the source set configuration follows suit as far as I learned, which also makes sense. But it might be that they reverted this change to first send it through a deprecation cycle.

Maybe something like this instead ?

Exactly, this is most often the best way to do some instrumentation.

But, if the post-processing changes for some reason but not the classes themselves. This will require to recompile everything in the module ?

Once, yes, that should be a viable trade-off usually.

Thanks !

Interesting.

@onenashev this is another kind of recipe for the Gradle cookbook.

OK, fair.