How to add generated sources to compile classpath without adding them to the main sourceSet?


(Martin Grotzke) #1

Hi,

we want to use generated JPA models (from hibernate metamodel generator) but checkstyle, findbugs & friends shall not check those files.

For this we added a new sourceSet “generated”, that allows us to exclude all files from checkstyle & co. Unfortunately, we cannot use the generated classes in our application as they’re not in the main sourceSets classpath (compileJava complains with “cannot find symbol” referring to some generated class).

Here’s the relevant parts of our build:

sourceSets {
  generated {
    java { srcDirs = [
        "$buildDir/generated-src/main/java"
      ] }
    compileClasspath += sourceSets.main.output
  }
}
  task generateMetamodel(type: JavaCompile, description: 'Hibernate JPA 2 Static-Metamodel Generator') {
  source = sourceSets.main.java
  classpath = configurations.compile + configurations.jpamodelgen
  options.compilerArgs = [
    "-proc:only",
    "-AaddGenerationDate=true",
  ]
  destinationDir = sourceSets.generated.java.srcDirs.iterator().next()
}
  compileJava.dependsOn generateMetamodel
  checkstyleGenerated { exclude '**/*' }
findbugsGenerated { exclude '**/*' }
pmdGenerated { exclude '**/*' }

When we add the generated sources to the compile java sources (via “compileJava.source(sourceSets.generated.java, sourceSets.main.java)”), compilation (with references to generated classes) works, but unfortunately checkstyle & co then also check these generated sources and reports lots of errors.

When we try to add the generated sources output to the compile classpath (via “compileJava.classpath += sourceSets.generated.output”) compileJava fails with a circular dependency error:

Circular dependency between the following tasks:
:connect-webapp:classes
\--- :connect-webapp:compileJava
     \--- :connect-webapp:generatedClasses
          \--- :connect-webapp:compileGeneratedJava
               \--- :connect-webapp:classes (*)

Is there any way to keep generated sources in a separate sourceSet (to be able to exclude them completely from checkstyle & co) and add the compiled, generated classes to the compileJava classpath?


Idiomatic way to generate source code that works in IDEs automatically without using specific IDE Gradle plugin
(Michael Brand) #2

I took a different approach to this, so I’m not sure if it will help. Basically, I created a separate project for the generated code, built a jar from that project, and then added a dependency from my main project to the generated project jar.

The generation project generates the class files into a subdirectory under “build” so that they’re not permanent.

The trick to making this all work is getting the inputs and outputs defined correctly.


(Ben Manes) #3

You can add an exclude rule to your

tasks.withType(Checkstyle) {
  source = sourceSets.main.allJava.matching {
    exclude '**/generated-src/**/*'
  }
}

This works well except if you treat Java warnings as errors, as often generated code has issues due to Java version skew (1.6 / 1.7). In that case you’ll want to use a custom sourceset so that the generated code has its own compile task that is configured to allow warnings. You can then make the generated code a dependency for the main sourceset.

Below is a template of steps that I’ve repeated a few times for code generation and custom sourcesets. I’m sure there’s a few unnecessary bits from debugging that could be trimmed.

configurations {
  codeGen
}
  sourceSets {
  codeGen {
    java.srcDir "${buildDir}/generated-src/"
  }
  main {
    runtimeClasspath += sourceSets.codeGen.output
  }
}
  compileCodeGenJava.options.compilerArgs = []
compileJava.dependsOn(compileCodeGenJava)
compileCodeGenJava.dependsOn(generateSources)
  dependencies {
  compile project(path: project.path, configuration: "codeGen")
  compile project(path: project.path, configuration: "codeGenCompile")
}
  project.afterEvaluate {
  dependencies {
    configurations.codeGen.allDependencies.each {
      compile it
      codeGenCompile it
    }
  }
}
  task codeGenJar(type: Jar, dependsOn: codeGenClasses, group: "Build",
    description: "Assembles a jar archive containing the generated classes.") {
  from sourceSets.codeGen.output
    afterEvaluate {
    baseName = "${baseName}.generated"
  }
}
  artifacts {
  codeGen codeGenJar
}

(Troy Hart) #4

There is a reference to ‘generateSources’ in: compileCodeGenJava.dependsOn(generateSources)

What is this reference?