Generate a Java file and include it in the sourceSet for compilation

As part of a build, I would want to generate one specific Java file from a template, then include it as part of the source set to be compiled.

Assuming that I might have something like

src/main/java/foo/bar.java
  src/main/java-templates/yin/yang.java.template

The first part is easy

task generateSource (type:Copy) {
  from('src/main/java-templates') {
    include '**/*.java.template'
  }
  into "${buildDir}/java"
  // Transform the content
  filter { .... }
  // And rename it to a .java file
  rename { ... }
}
  compileJava.dependsOn generateSource

The problem I have is, how to I add the generated files to the Java source set?

One way is to use the srcDir method of SourceDirectorySet

So something like

sourceSets {
    main {
        java {
            srcDir '<path to generated source>'
        }
    }
}

that would not work as it will result in a ‘Cannot add a SourceSet with name ‘main’ as a SourceSet with that name already exists.’

I don’t know how you’ve managed to produce that - can you provide the stack trace?

It is reproducible with something as simple as the following

apply plugin: 'java-base'
  sourceSets {
    main {
        java {
            srcDir new File( buildDir,'foo' )
        }
    }
}
  apply plugin: 'java'

Then run ‘gradle tasks --all’.

Context: If the example seems contrived, it is because it is a reflection of what happens in a plugin I am writing. I did not want to apply the ‘java’ plugin within my plugin, I just needed the source sets, so the ‘java-base’ is applied within my plugin. The idea was that the extra source will only get compiled when the user applies the ‘java’ plugin.

What you are doing using the code above is adding the main source set but what you want is to configure it if/when it’s added. The following will achieve that:

apply plugin: 'java-base'
sourceSets.matching { it.name == "main" } .all {
    it.java.srcDir new File(buildDir, 'foo')
}
apply plugin: 'java'

Sweet!