Search code examples
javagradledependencies

Gradle: how to declare a dependency to a specific configuration of a project programatically in java


Following the setup described in Simple sharing of artifacts between projects, we are in the special case where we have a multi module gradle build that produce different types of jars and we would like to declare a dependency to those jar in a configuration.

dependencies {
    instrumentedClasspath(project(path: ":producer", configuration: 'instrumentedJars'))
}

from the docs works great.

In the project dependency-tests I have a project that reproduce the setup (with different names, but the idea is the same).


But I am doing this in a Gradle-plugin and I would like to have the same declaration in java.

DependencyHandler dependencyHandler = project.getDependencies();

// this adds a dependency to the main jar of the 'producer' project:
dependencyHandler.add("instrumentedClasspath", project.getRootProject().findProject(":producer"));

// this is not working:
dependencyHandler.add("instrumentedClasspath", project.getRootProject().findProject(":producer").getConfigurations().getByName("instrumentedJars"));

Failing with:

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':printConf'.
> Could not resolve all dependencies for configuration ':instrumentedJars'.
   > Cannot convert the provided notation to an object of type Dependency: configuration ':producer:instrumentedJars' artifacts.
     The following types/formats are supported:
       - Instances of Dependency.
       - String or CharSequence values, for example 'org.gradle:gradle-core:1.0'.
       - Maps, for example [group: 'org.gradle', name: 'gradle-core', version: '1.0'].
       - FileCollections, for example files('some.jar', 'someOther.jar').
       - Projects, for example project(':some:project:path').
       - ClassPathNotation, for example gradleApi().
     
     Comprehensive documentation on dependency notations is available in DSL reference for DependencyHandler type.

* Try:
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.


Solution

  • project(...)
    

    inside the dependencies block comes from the DependencyHandler, and

    path: ":producer", configuration: 'instrumentedJars'
    

    is actually a map {"path"=":producer", "configuration"="instrumentedJars"}.

    So something like that should work in Java:

    Map<String, String> map = new HashMap<>();
    map.put("path", ":producer"); 
    map.put("configuration", "instrumentedJars");
    dependencyHandler.add("instrumentedClasspath", dependencyHandler.project(map)); 
    

    Note: When using Kotlin build script you can easily see types and declarations of functions and might be easier for discovering API. So in Kotlin project(...) in the dependencies block is an extension method defined as:

    fun DependencyHandler.project(
        path: String,
        configuration: String? = null
    ): ProjectDependency =
        uncheckedCast(
            project(
                if (configuration != null) mapOf("path" to path, "configuration" to configuration)
                else mapOf("path" to path)
            )
        )