Custom task fields not always initialized

Note: I have created a small, reproducible GitHub project to demonstrate the issue here.

In an effort to keep this thread short and easier to read I have posted all of the code to the repo above. The basic problem I am having is that we have a custom plugin with a custom task. This task essentially calls the Java XJC tool to convert .xsd files into .java files. For the purpose of this post the task just logs some data:

public class XjcTask extends SourceTask {

    DefaultXjc xjc

    XjcTask(DefaultXjc xjc, Project project) {
        this.xjc = xjc
	getLogger().lifecycle("XjcTask constructor: xjc.sourceDirs is ${xjc.sourceDirs}")

    void doStuff() {
        getLogger().lifecycle("XjcTask doStuff: xjc.sourceDirs is ${xjc.sourceDirs}")

We have a single sub-project with multiple directories of .xsd files, and our plugin registers a new task for each of those directories. The build.gradle for that sub-project looks like this:

apply plugin: "com.example.xjc"

xjc {
    serviceA {
            from("ServiceA") {
                include "ServiceA.xsd"
            from("CommonFiles") {
                include "Common.xsd"
        main = "ServiceA.xsd"
        sourceDirs = ["ServiceA","Common"]

The idea is the sub-project has 2 directories named ServiceA and Common, each with a .xsd file. The above gradle file would give us a new task named ServiceAXjc.

The problem I am having is that sometimes the constructor of our custom task sees null values for those 3 fields (contents, main, and sourceDirs). Specifically this happens when another, seemingly unrelated plugin, is applied in the parent project. For brevity that plugin’s code is included in the repository above.

So when that additional plugin is not applied, our XJC task outputs the following:

./gradlew :schemas:serviceAXjc
XjcTask constructor: xjc.sourceDirs is [ServiceA, ServiceB]

> Task :schemas:serviceAXjc
XjcTask doStuff: xjc.sourceDirs is [ServiceA, ServiceB]

But when the other plugin is applied, the same task outputs the following:

./gradlew :schemas:serviceAXjc

> Configure project :schemas
XjcTask constructor: xjc.sourceDirs is null

> Task :schemas:serviceAXjc
XjcTask doStuff: xjc.sourceDirs is [ServiceA, ServiceB]

I am having trouble figuring out how this unrelated plugin is causing those fields to be null when the XJC task constructor is executing. I have combed through it and cannot see any obvious reason.

I think I solved the problem. The unrelated plugin that was “interfering” with the XJC task constructor was using the tasks.whenTaskAdded API to dynamically add its own tasks. When I switched those calls to use tasks.configureEach it solved the problem of null values inside the XJC plugin.