[JLBP-22]

Declare all direct dependencies

If your code references a class—for example, by invoking a method in that class—declare a dependency that includes that class in your pom.xml, build.gradle, or equivalent. In Bazel this practice is called “strict deps”.

Code should not call methods, reference fields, or instantiate classes from indirect dependencies. These are dependencies of the declared dependencies. Projects that rely on indirect dependencies tend to break in unexpected ways when direct dependencies are upgraded.

For example, your project might declare a dependency on the Google HTTP Java Client which itself depends on the Apache HTTP Components. If so, it is possible to use the org.apache.http.client.utils.URLEncodedUtils class in your own project without explicitly declaring a dependency on Apache HTTP Components. However, you should add the dependency anyway so that if a future version of the Google HTTP Java Client no longer depends on Apache HTTP Components, your code still compiles. Strict dependencies also help static analysis tools better understand a project.

Code breakages due to indirect dependencies don’t just happen when a library is upgraded. They can also occur when dependency mediation selects a different version of a library’s dependency that does not include the necessary indirect dependency. Relying on indirect dependencies cause problems for clients with different dependency trees that don’t appear in your own code.

IDE autocomplete suggestions are a common way projects come to depend on indirect dependencies. When importing a new class, most IDEs only look to see if it’s present in the classpath, not whether it comes from a direct or indirect dependency.

The mvn dependency:analyze command lists dependencies a Maven project uses but hasn’t declared:

[WARNING] Used undeclared dependencies found:
[WARNING]    org.apache.maven.resolver:maven-resolver-impl:jar:1.4.1:compile
[WARNING]    org.apache.maven.resolver:maven-resolver-api:jar:1.6.1:compile
[WARNING]    org.apache.maven:maven-core:jar:3.6.3:compile
[WARNING]    org.apache.maven:maven-model-builder:jar:3.6.3:compile

These should be added to your pom.xml file.

The tool also lists dependencies the project declares but doesn’t use:

[WARNING] Unused declared dependencies found:
[WARNING]    com.google.cloud.tools:dependencies:jar:1.5.5-SNAPSHOT:compile
[WARNING]    com.google.truth:truth:jar:1.0.1:test
[WARNING]    junit:junit:jar:4.13.1:test
[WARNING]    org.mockito:mockito-core:jar:3.5.15:test

However its analysis of which dependencies aren’t used is not as accurate as its analysis of which dependencies are used. In particular, it reports dependencies used through reflection as unused, so be cautious when removing any allegedly unused dependencies.