Projects with generated sources and resources

In our projects we have a couple of custom plugins to generate both java sources and resources.

Let’s use generation of Resource-Constant Java-Classes and Compilation of JasperReports as examples for this post.

I’d like to define this like this in gradle

def resourceConstantsDir = file("$buildDir/generated-sources/main/i18n")
def jasperReportsDir = file("$buildDir/generated-resources/main/jasper")
task generateResourceConstants(type: GenerateResourceConstants) {
    from "src/main/i18n"
    into resourceConstantsDir
}
task compileReports(type: JasperCompile) {
    from "src/main/jasper"
    into jasperReportsDir
}
sourceSets {
    main {
        java {
            srcDir resourceConstantsDir, builtBy: generateResourceConstants
        }
        resources {
            srcDir "src/main/i18n"
        }
        output.dir jasperReportsDir, builtBy: compileReports
    }
}

and the IDE should automatically generate the Constant classes and compile the jasper reports. However, this does not work.

  • SourceDirectorySet.srcDir does not allow to define builtBy: generateResourceConstants
  • In Eclipse we had issues with defining generated resources dirs using SourceSet.output.dir
  • Neither task is run upon import of the project in any IDE.

My workaround so far is as follows:

apply plugin: 'eclipse'
sourceSets {
    main {
        java {
            srcDir resourceConstantsDir
            project.tasks.compileJava.dependsOn project.tasks.generateResourceConstants
            project.tasks.eclipseClasspath.dependsOn project.tasks.generateResourceConstants
        }
        resources {
            srcDir "src/main/i18n"
            srcDir jasperReportsDir
            project.tasks.processResources.dependsOn project.tasks.compileReports
            project.tasks.eclipseClasspath.dependsOn project.tasks.compileReports
        }
    }
}
tasks.eclipseProject.doFirst {
    // create external tool builder XMLs to launch compileReports and generateResourceConstants
    // including scan for changed files and refresh of project after execution
}
eclipse {
    project {
        buildCommand 'compileReports'
        buildCommand 'generateResourceConstants'
    }
}

However, this does only work with STS, not with Buildship – in fact, this is the only thing preventing us from switching right now.

Is there any other way of doing this with Buildship?

1 Like

Hi,
Sorry about not responding for a while. Rest assured, we’ll get back to you later, probably next week. Until that, it would speed up the analysis if you assembled a sample project what we can import to Buildship (and maybe STS).

Hi,

I did not have time to create a sample project, and will be on holidays
the next two weeks.

Tobias

Please see attached sample project. gradle-generated-sources-and-resources.zip (149.0 KB)

The build does generate resource constant classes for each resource bundle in src/main/i18n. In addition it generates one index file resourcebundles.idx to list all resource bundles. The main class does list all bundles and all keys using both the generated index file and the generated constant class files.

When using a simple text editor and the command line, when doing any of the following:

  • add a new bundle
  • add a new key to a bundle
  • remove a key from a bundle
  • remove a bundle

a call to

./gradlew run

will show the changes.

But if I import the project in idea or eclipse, it does not work. E.g. in STS

  • when the project is clean, the generated constant classes are not visible to eclipse. You need to build on the command line and refresh the project using the STS “refresh all” menu
  • Execution of the main class ListBundles leads to a NullPointerException, because the generated index file is not on the classpath

When using ./gradlew eclipse, I need to first call ./gradlew assemble, otherwise the source folder of the generated constant classes is not found. And after every change to the bundles, I need to switch to the command line to ./gradlew assemble.

Thanks. We will look into it, but it will take a week or so before we get to that since we are currently preparing for the Mars 1 release. Thanks for your patience.

One remark already: we intend to provide a way to model in Gradle what tasks to run during an import through the Tooling API. We have not decided yet how to model this explicitly.

The thing is that Buildship and the Gradle ‘eclipse’ plugin is (almost) entirely independent, so specifying the buildCommand will have no effect to the imported project.

I suggest you to try out the continuous build feature of Gradle. From Buildship it is quite easy, just create a new Gradle run configuration (executing a task automatically creates one), open the configuration’s dialog, and on the Arguments tab specify --continuous. If the inputs and outputs of your task is specified correctly, then the build will run automatically when you change something.

The buildCommand is only part of my workaround so far to get it somehow to work with STS.

From an end user perspective. Let’s suppose following scenario:

  • New developer with nothing but java, git and Eclipse installed
  • She is tasked with fixing a bug

First she needs to setup her development machine. She heads to the checklist…

You are suggesting:

  1. Checkout the project (git clone …)
  2. cd into the directory
  3. ./gradlew build // we must do this first, because otherwise some folders do not exist
  4. Import the project into Eclipse (using Buildship)
  5. Create a gradle run configuration in Eclipse and alter it to contain --continuous
  6. From now on, after each restart of eclipse, first start the continuous gradle task

3, 5, and 6 can be compressed to "execute ./gradlew build --continuous in the shell before starting Eclipse

I am suggesting:

  1. Checkout the project
  2. Import the project into Eclipse (using Buildship)

Decide yourself, which one has better usability.

1 Like

You are correct, my proposal is far less convenient than it could be. It was only a suggestion which works without waiting for a feature being implemented in Buildship.

We have plans to support more features from the Gradle eclipse plugin in Buildship, but I can’t give any estimates.

Was there any progress in Buildship in regards to this workflow?

We have several things that we would like generated and included in the sources for for eclipse without having to manually build those generated sources first. (think swagger, querydsl)

Hi Nick,

this feature is not on our priority list at the moment. In case you or someone else is interested, we would happily welcome contributions and guide the contributor through the process.

Cheers,
Stefan

Has there been any progress in Buildship in regards to this workflow?

I’m updating our builds from 2.10 up to 4.6 and we have annotation processors that generate Hamcrest matchers from a testSupport sourceSet for use by test and intTest.

Well, not much has happened since. There is the Run tasks on synchronization story which we plan to implement once we finish with the 3.0 release, and which would be probably helpful for your use case.