Controlling plugin application order

I’ve got an issue where my custom build logic is checking whether the java plugin is applied, but it appears my plugin is being applied before the java plugin, making it appear as if the java plugin is not present. What’s the right way to deal with this sort of timing issue?

gradle-plugin-ordering.zip (235.3 KB)
I’ve attached a SSCCE; if it works, running gradlew :client:tasks should have an entry for a javadocJar task. If not, it will fail with the message “Java not configured for :client”.

You should never write code that explicitly checks if a plugin has currently been applied. This type of logic is considered bad practice. Rather, one of two things should be true:

  • Applying your plugin requires the Java plugin. You should have your plugin apply it. Plugin application is idempotent, so it’s fine if it’s applied in the build itself or not. It will still only be applied once.
  • Applying the Java plugin with your plugin is optional. You should register an action that configures when the Java plugin in applied, but otherwise do nothing by using withPlugin(...) in the PluginManager (Gradle API 7.4.2).
1 Like

Thanks James, withPlugin was definitely a key piece I was missing. How does that work for a more complex scenario though? Like doing X when the java plugin is applied but the war plugin isn’t, and doing Y when the war plugin (which also applies the java plugin) is applied?

Would I need to use withPlugin("war"){} to set a flag in my plugin class, and just skip the irrelevant tasks? Or is there a way to prevent my tasks that are only relevant to plain java from being added at all when the war plugin is applied?

I don’t know exactly what sort of scenario you’re trying handle, but as a generalization, avoid the complex scenarios where you might initially want conditional logic.

You would effectively skip them, not prevent them from being added. You will never know when the Java plugin is applied that the War plugin will not be applied. For the Java plugin itself, a jar task is added. When you add the War plugin, a war task is added. You generally would not use the jar task, but it is still there and just not executed by the normal lifecycle tasks. Your logic can do the same. Either change the configuration of the tasks that depend on your tasks added by the Java plugin being present that are no longer desired when the War plugin is later applied or disable them.

If there is something conceptually different about these projects, that really makes you want to avoid having the tasks that should only be used when war is not, I would break your plugin up into multiple plugins. Split them up and apply com.example.webappplugin to some projects and com.example.libraryplugin to others rather than trying to have com.example.doeverythingplugin applied to everything. Normal object-oriented principles still apply here, so your Plugin classes can be very lightweight (same JAR, just a Plugin class that takes the place of the conditional) and just delegate to the appropriate collaborators that handle the details. This effectively makes your plugin usage more declarative instead of relying on behind the scenes imperative logic.

1 Like

Sounds good, just wanted to be sure I wasn’t overlooking something