Skip to content

Linkage Checker with Gradle

Tomo Suzuki edited this page Aug 12, 2021 · 13 revisions

The Linkage Checker Gradle plugin verifies that a project's classpath does not have any linkage errors. For a Gradle project, we provide two ways to check its dependency graph: Gradle's way and Maven's way.

  • Gradle's way: When Gradle builds dependency graphs and it encounters multiple versions of the same library, it selects the highest versions of library in the transitive dependencies.
  • Maven's way: When Maven builds dependency graphs and it encounters multiple versions of the same library, it selects the closest (the minimum hop from the root) version to the root project.

If you have Gradle project that produces a library which Maven users depend on it, it's worth checking your library's dependency in Maven's manner.

Check Gradle project's dependency in Gradle's way

To check Gradle project's dependency graph in Gradle's way, use the Linkage Checker Gradle plugin. The plugin installs "linkageCheck" task to the project and specify the configuration you want to check.

plugins {
  id "com.google.cloud.tools.linkagechecker" version "1.5.10"
}

linkageChecker {
  configurations = ['compile']
  reportOnlyReachable = true
}
// Run build task first to generate JAR file of this project
linkageCheck.dependsOn('build')

Run the task to detect linkage errors:

$ ./gradlew linkageCheck
...
> Task :linkageCheck FAILED
Linkage Checker rule found 81 errors:
Class com.jcraft.jzlib.JZlib is not found;
  referenced by 4 class files
    io.grpc.netty.shaded.io.netty.handler.codec.spdy.SpdyHeaderBlockJZlibEncoder (io.grpc:grpc-netty-shaded:1.28.1)
    io.grpc.netty.shaded.io.netty.handler.codec.compression.JZlibEncoder (io.grpc:grpc-netty-shaded:1.28.1)
...

What is a "configuration"?

A configuration in Gradle is a list of dependencies. In your build.gradle, you declare dependencies of your project with dependencies clause. It actually adds the dependency to the configuration you specify in the arguments to the clause. For example, assume you have a build.gradle with the following dependencies:

dependencies {
  compile 'com.google.cloud:google-cloud-logging:1.101.1'
  compile 'io.grpc:grpc-core:1.29.0'
}

This adds the two dependencies to compile configuration. In Gradle Java plugin, when Gradle "compiles" your project it resolves the dependencies of the compile configuration and supplies the Java compiler. Another example is testCompile configuration. When Gradle compiles tests, it supplies the dependencies of testCompile configuration.

Check Gradle-generated Maven artifact in Maven's way

A Gradle module often outputs a Maven artifact. For a library developed in Gradle, it's important to ensure the dependency graph of the Maven artifact in Maven's manner because Maven users may use the library and Maven

To detect linkage errors in Maven artifacts generated by a Gradle project, you can first install the artifact in Maven local repository using Gradle's Maven Publish Plugin and then run LinkageCheckerMain with your artifact coordinates.

// Separate configuration (class path) for Linkage Checker
configurations { linkageChecker }
dependencies {
  linkageChecker "com.google.cloud.tools:dependencies:1.5.10"
}

project.task('runLinkageChecker', type: JavaExec) {
  // Replace 'MavenJava' with your publication name
  dependsOn project.getTasksByName('publishMavenJavaPublicationToMavenLocal', true)
  classpath = project.configurations.linkageChecker
  main = 'com.google.cloud.tools.opensource.classpath.LinkageCheckerMain'
  args '-a', 'com.example:foo:0.1.0-SNAPSHOT' // the coordinate of the Maven artifact
}