8

Having the following multi-module-setup:

multi
├── projA
│   └── build.gradle.kts
├── projB
│   └── build.gradle.kts
├── build.gradle.kts
└── settings.gradle.kts

with the following content (abbreviated):

  • settings.gradle.kts

    rootProject.name = "multi"
    include("projA", "projB")
    
  • projA\build.gradle.kts

    dependencies {
        implementation("important-library:1.0")
    }
    
  • projB\build.gradle.kts

    dependencies {
        implementation(project(":projA"))
    }
    

Why don't I have access to that importantlibrary:1.0 from projB?

What works: if I have a class within projA that uses the library, it works perfectly even if that class is called from a class within projB (so indirect access works). Directly accessing any class from importantlibrary:1.0 within projB doesn't work (unresolved reference).

What am I missing here? Or what needs to be set up so that it works?

Gradle version: 5.6.1

Roland
  • 22,259
  • 4
  • 57
  • 84

3 Answers3

6

I think a good way to achieve what you want would be to use api instead of implementation. implementation is meant to only keep the dependency inside the module, while api is meant to export them along with the module. The dependencies for projA would then become:

dependencies {
    api("important-library:1.0")
}

This is the link to the official documentation: https://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_separation

Roland
  • 22,259
  • 4
  • 57
  • 84
gscaparrotti
  • 663
  • 5
  • 21
  • can you elaborate on that a bit further? I mean this is certainly working for the classes in question, but the next step would be to build a fat jar... which dependencies should then be included and which not? how would you resolve that? Coming from Maven I thought `compile` would be replaceable with `implementation` and `provided` with `api` ... and it nearly worked out... the `configuration = "default"` resolved the last issue and now it all seems to work similar as it worked in Maven... – Roland Feb 20 '20 at 14:03
  • if my assumption is wrong however, then I am all ears, how it actually should be and how I would resolve something like a fat jar... – Roland Feb 20 '20 at 14:03
  • Seems as if my assumption was not correct... need to study more :-) will clean up some comments... – Roland Feb 20 '20 at 15:21
3

I found lots of sources mentioning configuration to handle how transitive dependencies are dealt with. Digging deeper I found that the default configuration should make the runtime, runtimeOnly and implementation available to the referencing project.

Either I misinterpreted "default" here or you really need to call it using the "default"-configuration explicitly. Declaring the dependency as follows in projB, made the dependencies from projA available to projB as well:

implementation(project(":projA", "default"))
// or with named parameters:
implementation(project(path = ":projA", configuration = "default"))

Wondering whether this is/was really intended or whether that is rather an unfortunate default value for the configuration-parameter of the project-function.

Roland
  • 22,259
  • 4
  • 57
  • 84
2

There are 2 themes: transitivity of dependencies and /src as dependency

  • Dependency transitivity

We use api so that the dependency can be exported to the higher hierarchy of modules.

build.gradle.kts (:library_base)

dependencies {
    api("group", "name", "version")
}

build.gradle.kts (:common)

dependencies {
    implementation(project(":domain"))
    implementation(project(":library_base"))
}
  • Transitivity of /src as dependency

We pass "default" in the second parameter as configuration to be able to import the /src from the lower hierarchy of modules.

build.gradle.kts (:feature_a)

dependencies {
    implementation(project(":common", "default"))
}

To be able to access from :feature_a to /src of eg. :domain we use "default" as configuration and to be able to access the dependencies of :library_base we make sure that they are defined with api in that module so that they can be exported.

GL

Source

Braian Coronel
  • 22,105
  • 4
  • 57
  • 62