Home > other >  Gradle project does not export implementation-dependency to other projects
Gradle project does not export implementation-dependency to other projects

Time:09-11

My gradle project contains 3 sub-projects with one source file each:

root-project\
    sub-project-abstract\
        ...AbstractFoo.java
    sub-project-commons\
        ...ConcreteFoo.java (extends AbstractFoo)
    sub-project-main\
        ...Main.java (instantiates ConcreteFoo)

build.gradle of sub-project-commons:

dependencies {
    implementation(project(:sub-project-abstract))
}

build.gradle of sub-project-main:

dependencies {
    implementation(project(:sub-project-commons))
}

The Main-class in sub-project-main is aware of ConcreteFoo, however, compilation fails with cannot access AbstractFoo.

For some reason, I expected sub-project-commons to "export" ConcreteFoo and AbstractFoo, since it's a implementation-dependency. Or in other words, form the perspective of sub-project-main, AbstractFoo is a transitive dependency.

However, this doesn't seem to be the case. I know that I could probably make it work by explicitly adding sub-project-abstract as a direct dependency to sub-project-main. However, that's something I want to avoid due to the nature of the commons project (my actual project contains up to 10 subprojects, and it should be possible to reuse the commons-project without declaring a dependency to sub-project-abstract every single time the commons-project is referenced.

Is there a way to make the Main-class aware of AbstractFoo without directly declaring sub-project-abstract as a dependency (but indirectly via sub-project-commons)?

CodePudding user response:

This is expected behavior for the implementation configuration. You should apply the Java Library Plugin and use the api configuration.

The key difference between the standard Java plugin and the Java Library plugin is that the latter introduces the concept of an API exposed to consumers. A library is a Java component meant to be consumed by other components. It’s a very common use case in multi-project builds [emphasis added], but also as soon as you have external dependencies.

The plugin exposes two configurations that can be used to declare dependencies: api and implementation. The api configuration should be used to declare dependencies which are exported by the library API, whereas the implementation configuration should be used to declare dependencies which are internal to the component.

[...]

Dependencies appearing in the api configurations will be transitively exposed to consumers of the library, and as such will appear on the compile classpath of consumers. Dependencies found in the implementation configuration will, on the other hand, not be exposed to consumers, and therefore not leak into the consumers' compile classpath. [...]

In sub-project-commons (Kotlin DSL):

plugins {
    ...

    `java-library`
}

...

dependencies {
    api(project(":sub-project-abstract"))
}

...
  • Related