processResources does not copy to correct dir

The documentation states resources are copied to the corresponding classes dir.

From https://docs.gradle.org/current/userguide/java_plugin.html, Table 23.1:

processResources - Copies production resources into the production classes directory.
processTestResources - Copies test resources into the test classes directory.

However, building a very simple example project, I see build/resources/main and build/resources/test dirs created. Any main and test resources exist there. When running tests, both the classes and resources dirs are added to the classpath.

Not only does this not match the documentation, but it is also very problematic for properly reading resources in tests. If trying to read a resource directory (for example, to do a listing on test support files), the first element in the classpath that has that resource “wins”. So in this case, the classes dir comes before resources on the classpath, and doing a getClass().getResource("/some/path") looks like an empty directory.

Bump. Any thoughts here?

This is the intended behavior. I’ve updated the documentation to reflect this.

As for your test classpath issue you can probably get around it by explicitly ordering the resources directory ahead of the classes dir on the classpath.

sourceSets {
    test {
        compileClasspath = files(main.output.resourcesDir, main.output.classesDir, configurations.testCompile)
        runtimeClasspath = files(test.output.resourcesDir, test.output.classesDir, main.output.resourcesDir, main.output.classesDir, configurations.testRuntime)
    }
}

Also there are solutions to finding all classpath resources that match a given pattern that are more robust and less dependent on classpath ordering.

Hi,

I don’t think having to use a third-party library to lookup resources should be necessary. Resources belong with the classes, this is what every other build system for java I know does. If you were to jar the classes and resources, they would be in the same directory hierarchy, and looking up a resource dir would work.

With that said, I got around the issue by redirecting the resources output dir:

sourceSets {
  main {
    output.resourcesDir = "build/classes/main"
  }
  test {
    output.resourcesDir = "build/classes/test"
  }
}

However, I still believe the original docs implied the correct behavior.

Typically it isn’t, but since the same directory could exist in multiple places on the classpath (in multiple jars) it’s the most robust solution.

This is done primarily for separation of build outputs. Gradle tasks generally map 1:1 with an output directory. This allows us to do things like partial cleans (i.e. gradle cleanProcessResources) as well as being key to incremental build support.