gradledependenciestransitive-dependencymaven-publish

Gradle maven-publish dependency scope


I have a pretty simple Gradle Kotlin project.

plugins {
    id 'application'
    id 'maven-publish'
}

repositories { mavenCentral() }

dependencies {
     compile 'com.google.guava:guava:31.1-jre'      // 'compile' is deprecated
}

publishing {
    publications {
        maven(MavenPublication) {
            groupId = 'de.mabe'; artifactId = 'project1'; version = '1.0'
            from components.java
        }
    }
}

When I start gradle publishToMavenLocal it generates a correct pom file with a correct dependency:

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>31.1-jre</version>
    <scope>compile</scope>             <!-- this scope is important -->
</dependency>

Now I replaced the compile with implementation in the gradle script.

implementation 'com.google.guava:guava:31.1-jre'

Unexpectedly this changes the scope in the pom file from compile to runtime.

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>31.1-jre</version>
    <scope>runtime</scope>             <!-- compile EXPECTED ?!?! -->
</dependency>

What do I have to do to get the previous pom back?


Solution

  • That is by design. The semantics of the implementation configuration is to declare dependencies that are internal to a module. By mapping it to the runtime scope of a Maven pom, it ensures that it doesn't leak onto the compilation classpath of consumers. This has a few advantages like being more free to swap out transitive depencies with less risk of affecting consuming modules, to make compilation faster and more.

    If you need to make a transitive dependency part of the compile scope, i.e. expose it on the compilation classpath of consuming projects, you need to use the api configuration instead. This is available by applying the java-library plugin.

    For example (Groovy DSL):

    plugins {
        id 'java-library'
        id 'maven-publish'
    }
    
    dependencies {
        implementation 'org.apache.commons:commons-math3:3.6.1' // <- Maps to the Maven runtime scope 
        api 'com.google.guava:guava:30.1.1-jre' // <- Maps to the Maven compile scope
    }
    
    publishing {
        publications {
            maven(MavenPublication) {
                groupId = 'de.mabe'; artifactId = 'project1'; version = '1.0'
                from components.java
            }
        }
    }
    

    You can read more about the separation between API and implementation in the Gradle user guide here.