Skip to content

Linkage Checker Enforcer Rule Tutorial

Tomo Suzuki edited this page Aug 31, 2021 · 23 revisions

In this tutorial, you’ll learn how to use the enforcer rule to statically detect Java diamond dependency conflicts. The target audience is Java developers who already know Git, Maven command (mvn), and JDK 8.

Setup

Checkout project via Git. Our project contains example-problems directory.

$ git clone https://github.com/GoogleCloudPlatform/cloud-opensource-java.git
$ cd cloud-opensource-java/example-problems/no-such-method-error-signature-mismatch

The following commands assume that this no-such-method-error-signature-mismatch as current working directory.

Compile and run the project. You observe NoSuchMethodError:

# in no-such-method-error-signature-mismatch directory
$ mvn clean compile exec:java
...
java.lang.NoSuchMethodError: com.google.common.base.Verify.verify(ZLjava/lang/String;Ljava/lang/Object;)V
    at io.grpc.internal.DnsNameResolver.maybeChooseServiceConfig (DnsNameResolver.java:514)
    at io.grpc.internal.App.main (App.java:31)
...
[INFO] BUILD FAILURE

Now you have a Maven project with a diamond dependency conflict.

Diagnosis of Linkage Error

(This section can be skipped if you just want to learn Linkage Checker Enforcer Rule.)

Linkage Checker Enforcer Rule Tutorial Problem Diagnosis

Linkage Checker Enforcer Rule

The project already has the Linkage Checker Enforcer Rule in its plugin element to the pom.xml. Run the enforcer rule as below.

# in no-such-method-error-signature-mismatch directory
$ mvn verify
...
[INFO] --- maven-enforcer-plugin:3.0.0-M2:enforce (enforce-linkage-checker) @ no-such-method-error-example ---
...
Class javax.jms.QueueSession is not found;
  referenced by 1 class file
    org.apache.log.output.jms.JMSQueueTarget (logkit-1.0.1.jar)
Class javax.jms.TextMessage is not found;
  referenced by 1 class file
    org.apache.log.output.jms.TextMessageBuilder (logkit-1.0.1.jar)
(guava-20.0.jar) com.google.common.base.Verify's method verify(boolean arg1, String arg2, Object arg3) is not found;
  referenced by 3 class files
    io.grpc.internal.ServiceConfigInterceptor (grpc-core-1.17.1.jar)
    io.grpc.internal.JndiResourceResolverFactory (grpc-core-1.17.1.jar)
    io.grpc.internal.DnsNameResolver (grpc-core-1.17.1.jar)

[WARNING] Rule 0: com.google.cloud.tools.dependencies.enforcer.LinkageCheckerRule failed with message:
Failed while checking class path. See above error report.
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------

Now you can detect NoSuchMethodErrors in the project as part of the build.

reportOnlyReachable flag

In the output of the previous step, you might notice that it showed errors on seemingly irrelevant classes such as javax.jms.QueueSession and javax.jms.TextMessage. The project might not use the classes. To filter errors on unused classes, you can set reportOnlyReachable flag to true.

  <LinkageCheckerRule
      implementation="com.google.cloud.tools.dependencies.enforcer.LinkageCheckerRule">
      <reportOnlyReachable>true</reportOnlyReachable>
  </LinkageCheckerRule>

Rerun the build again.

$ mvn verify
...
[INFO] --- maven-enforcer-plugin:3.0.0-M2:enforce (enforce-linkage-checker) @ no-such-method-error-example ---
[ERROR] Linkage Checker rule found 1 reachable error. Linkage error report:
(guava-20.0.jar) com.google.common.base.Verify's method verify(boolean arg1, String arg2, Object arg3) is not found;
  referenced by 1 class file
    io.grpc.internal.DnsNameResolver (grpc-core-1.17.1.jar)

[WARNING] Rule 0: com.google.cloud.tools.dependencies.enforcer.LinkageCheckerRule failed with message:
Failed while checking class path. See above error report.
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  3.211 s

The enforcer rule now shows only relevant errors for the project.

Fix the Linkage Error

The NoSuchMethodError occurred because the two artifacts and their transitive dependencies are not compatible with each other. To fix the problem, you change the version of the google-api-client:

Run the linkage checker enforcer rule again. This time you don’t see the errors:

$ mvn verify
...
[INFO] --- maven-enforcer-plugin:3.0.0-M2:enforce (enforce-linkage-checker) @ no-such-method-error-example ---
[INFO] No reachable error found
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

Run the main class again. This time it succeeds to run without NoSuchMethodError:

$ mvn clean compile exec:java
...
[INFO] --- exec-maven-plugin:1.6.0:java (default-cli) @ no-such-method-error-example ---
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------