Gradle resolves dependencies too early in lifecycle ... how to prevent and catch this behavior

I’m noticing that for some projects, gradle will resolve dependencies during the configuration step. This is perfectly normal for plugins and other deps on the gradle classpath. The problem is that is very easy to accidentally tell gradle to resolve compile and build dependencies during configuration, before any compile or build tasks are even executed.

How do you use configuration objects in copy, zip, and jar tasks so that gradle does not resolve them early?

I think this behavior should also throw a warning to the user because 99% of the time you do not want to download dependencies that will not even be required for the execution tasks. Another option would be to have runtime switch to break the build if a project configuration is being resolved in the configuration step. Thoughts?

1 Like

Configurations get resolved when their contents are first requested. As long as Gradle has distinct configuration and execution phases, it will always be the build script or plugin author’s responsibility to do as little work as possible in the configuration phase. We all know this can be tricky, but I don’t think that warnings (which will invariably result in false positives) or special handling of configuration resolution (which is just one instance of a much more general problem) is the solution.

Other than the gradle build classpath and plugins, I can’t think of any other reason why you would need to download resolved dependencies during the configuration phase. Because of this, why can’t gradle wait till a task is executing to download the resolved dependencies? Right now it feels like dependencies are retrieved early only to cover a few edge cases that most users would not hit, and this ends up impacting all the gradle builds across the board for every user.

I basically have two cases where gradle pulls in deps early. The first case is where i need to get a transitive list of deps, so I can exclude them from earlib configurations. I can fix this case, but it is a good example of where resolving deps in the configuration could be necessary, but also downloading the jars at that point is unnecessary.

The second case uses a dependency to create generated tasks. I need to resolve the names of the dependencies to generate the ‘outputs.files’ command for that tasks. I don’t think there is a work around possible for this. Again, downloading jars just to access the filename of the deps is unnecessary. Why does gradle force this behavior?

If postponing dependencies downloads until task execution is not possible, could there be a concept of a “layz” dependency, and then have an explicit ‘resolve’ method to call before using the dependencies during the task execution? This addition would be backward compatible and allow users more control over when deps are downloaded.

Artifacts won’t be downloaded unless you request them. If you just want to analyze dependencies, try the ‘Configuration#incoming’ or ‘Configuration#resolvedConfiguration’ API.

Yes, Configuration#incoming was helpful. Thanks for that. However the API docs of Configuration.getResolvedConfiguration says:

resolvedConfiguration

Resolves this configuration. This locates and downloads the files which make up this configuration, and returns a ResolvedConfiguration that may be used to determine information about the resolve (including errors).

It’s possible to use incoming.dependencies for names, but it doesn’t look like the interface exposes the file extension. Is there a hidden API to get the file extension when the dependencies are declared in the form ‘group:module:version@ext’ ??