Transitive runtime dependencies are treated as compile


(Eduard Dudar) #1

We have the following linear dependency between projects. Each project depends on other one through binary artifacts as compile 'X.jar' and not compile project(':X').

A depends on B, B on C and C on D.

B and C are published to maven repository with 'maven-publish' plugin so they all are exposed to this issue: Maven-publish plugin generated pom making dependency scope runtime. Basically their POM files has runtime dependencies only.

Then I use compile 'B:1.0.+' in project A and for some reason I see all dependencies as compile:

compile - Compile classpath for source set 'main'.
+--- A:1.0.+ -> 1.0
|    +--- B:1.0.+ -> 1.0
|    |    +--- C:1.0.+ -> 1.0
|    |    |    +--- D:+ -> 1.0

Shouldn’t B, C and D belong to runtime scope only?

Thanks!


(Michael Schaefers) #2

I am experiencing a similar problem with current gradle 2.10 (also tested with 2.9):

given the following example files

settings.gradle

include ':A', ':B'

build.gradle

allprojects {
    apply plugin: 'java'
    apply plugin: 'maven'

    repositories {
        mavenLocal()
        mavenCentral()
    }
}

project(':A') {
    dependencies {
        compile project(':B')
    }
}

project(':B') {
    dependencies {
        runtime "org.slf4j:slf4j-log4j12:1.7.13"
    }
}

Running

gradle :A:dependencies

leads to

:A:dependencies

------------------------------------------------------------
Project :A
------------------------------------------------------------

archives - Configuration for archive artifacts.
No dependencies

compile - Compile classpath for source set 'main'.
\--- project :B
     \--- org.slf4j:slf4j-log4j12:1.7.13
          +--- org.slf4j:slf4j-api:1.7.13
          \--- log4j:log4j:1.2.17

default - Configuration for default artifacts.
\--- project :B
     \--- org.slf4j:slf4j-log4j12:1.7.13
          +--- org.slf4j:slf4j-api:1.7.13
          \--- log4j:log4j:1.2.17

runtime - Runtime classpath for source set 'main'.
\--- project :B
     \--- org.slf4j:slf4j-log4j12:1.7.13
          +--- org.slf4j:slf4j-api:1.7.13
          \--- log4j:log4j:1.2.17

testCompile - Compile classpath for source set 'test'.
\--- project :B
     \--- org.slf4j:slf4j-log4j12:1.7.13
          +--- org.slf4j:slf4j-api:1.7.13
          \--- log4j:log4j:1.2.17

testRuntime - Runtime classpath for source set 'test'.
\--- project :B
     \--- org.slf4j:slf4j-log4j12:1.7.13
          +--- org.slf4j:slf4j-api:1.7.13
          \--- log4j:log4j:1.2.17

BUILD SUCCESSFUL

Total time: 2.441 secs

While I am expecting that the runtime dependencies of B do not show up as compile dependencies of A, it’s hard to believe that this is actually a bug and not a feature. Can someone tell me if/why this behavior is OK?

For this example, referencing org.apache.log4j.Logger in project A even compiles successfully via gradle assemble.


(Michael Schaefers) #3

I posted my problem at StackOverflow.com


#4

I am pretty sure you should find how dependencies are organised.
As far as I remember runtime extends from compile. Same is applied for testCompile and testRuntime. If you don’t like what Gradle default conventions offer just create your own configurations add fill them.


(Michael Schaefers) #5

I am totally OK with the default conventions of Gradle, and with the fact that runtime extends from compile (which is “every compile dependency is also a runtime dependency”). Thats what we can see looking at the runtime dependencies of project A. Your statement however did not explain the shown compile dependencies of project A:

The example given just shows that the runtime dependency from project B is also a compile dependency from project A. The compile dependencies of project A should only contain project B, because compile does not extend from runtime.


(Lance Java) #6

See Peter’s answer here

compile project(':B') will use the project’s default configuration which extends from runtime. Use this instead

compile project(path: ':B', configuration: 'compile')

(Michael Schaefers) #7

Thanks a lot - you saved my day :slightly_smiling:


(Robert Stoll) #8

I have the same problem with gradle 4.5.1
Following setting, I depend on project A. Its a maven project and has defined a dependency to project B with <scope>runtime</scope>
When I define a dependency to A with:

dependencies {
   compile "groupId:projectA:version"
}

Then project B is included in the compileClasspath. How do I need to define the dependency so that project B is still treated as runtimeOnly dependency?

Found a solution => https://github.com/gradle/gradle/issues/977