Unsafe configuration resolution warning in a single project

I’ve encountered the following warning when running on a single project build and Gradle 6.3

The configuration :runtimeClasspath was resolved without accessing the project in a safe manner.  This may happen when a configuration is resolved from a different project.  See https://docs.gradle.org/6.1.1/userguide/viewing_debugging_dependencies.html#sub:resolving-unsafe-configuration-resolution-errors for more details. This behaviour has been deprecated and is scheduled to be removed in Gradle 7.0.

The warning and the linked docs point to possible problems when resolving configurations that cross project boundaries. However in this case there are no additional projects, just the one. I wonder then what could be the cause of this problem. The project applies a plugin that calculates a “Class-Path” manifest entry with the following code

If this piece of code is omitted then no warning occurs. Configurations are not eagerly resolved anywhere else by the plugin nor the project itself. Any clues on how to solve this issue?

I think Gradle is basically confused because you’re configuring a task (the jar task) within a configuration block of the configuration itself. And that within the configuration block of the configuration, you’re resolving the configuration.

It looks like you’re trying to set the Class-Path property of a jar file in the manifest using the runtime classpath configuration.

Before going on how to do this properly, let me explain why it’s a bad idea to resolve the runtimeClasspath configuration like this. The named method will let you configure the runtime classpath configuration. Which means, you could add dependencies, add “extends from”, set it’s “resolvable” flag, etc… And within that configuration block (remember that there can be many, from different plugins), you are actually resolving the configuration:

c.resolvedConfiguration.resolvedArtifacts

This isn’t right, because you’re actually doing something too early (resolving when the configuration’s configuration (!) is not finished), and that you’ll be resolving dependencies at configuration time (very bad for performance).

Instead, because that’s the jar task that you want to configure, you should configure the jar task and tell it what you’re going to do:

jarTask.configure {
    inputs.files(configurations.runtimeClasspath) // "Hey, to be able to execute and be configured properly, I need the runtime classpath to be resolved
    doFirst {
        // now I can configure the manifest
        def artifacts = configurations.runtimeClasspath.files (or `configuration.incoming.resolutionResult` if you need a better API than just the flat list
    }
}

Doing this, the manifest entry is configured at execution time, and the runtimeClasspath configuration is only going to be resolved if, and only if, you execute that task. There’s currently no API to configure the manifest lazily that I’m aware of, hence why it’s done in a `doLast. But remember: never, ever, try to resolve configurations during configuration phase, especially to configure other tasks. This is doomed to fail.

I was actually wrong, you can configure the manifest classpath entry with a provider { ... } so no need to do it as execution time.