gradle-lint-plugin icon indicating copy to clipboard operation
gradle-lint-plugin copied to clipboard

Lint rule to detect incorrect 'implementation' dependency declarations

Open alexkleiman opened this issue 7 years ago • 0 comments

As we've seen in #126, Gradle's java-library plugin supports new dependency configurations, implementation and api.

It can be difficult to tell when to declare a dependency as implementation vs api. For example, consider the following two modules:

module a

a/Foo.java:

public class Foo {
  public static ImmutableList<Integer> emptyIntegerList() {
    return ImmutableList.of();
  }
}

a/build.gradle:

dependencies {
  // Should be an 'api' dependency
  implementation group: "com.google.guava", name: "guava", version: "21.0"
}

module b

b/Bar.java:

public class Bar {
  public void callModuleA() {
    Foo.emptyIntegerList();
  }
}

b/build.gradle:

dependencies {
  implementation project(":a")
  // Import masks the problem in a/build.gradle
  implementation group: "com.google.guava", name: "guava", version: "21.0"
}

Module a's dependency on guava should be declared as an api dependency, because the guava type ImmutableList is exposed in Foo's public API. This could cause compilation errors, because modules which depend on a will not have the guava library provided to their compilation classpaths.

In our case, however, we don't see any compilation errors. This is because a's dependent module, b, also declares a dependency on guava. Thus, while b doesn't get guava from a, it gets it from a different source, and we have everything we need to compile.

This can lead to problems if module b ever stops declaring a dependency on guava (which would be a reasonable thing to do, because the dependency declaration shouldn't be necessary). This is particularly pernicious when publishing libraries consumed by third parties. These sorts of errors, which prevent any use of the given library, may not be discovered until after code has already shipped, at which point the only recourse is to issue a new release of the library in question.

It would be very nice if nebula-lint provided a rule to detect instances where API dependencies are mistakenly declared as implementation dependencies. Section 48.3 of the Gradle documentation, "Recognizing API and implementation dependencies", provides more details on what should be considered API vs implementation dependencies.

I have uploaded a tar file containing a simple Gradle project which makes it easy to reproduce this project. See the README for more details.

alexkleiman avatar Jul 13 '17 23:07 alexkleiman