Require Direct Dependency Declarations at Compile Time

I would like the compile task to fail unless I have an explicit dependency declaration for each compile time dependency of the source files (e.g., the imports from other projects & modules).

I’ve tried turning the “compile” configuration’s “transitive” property to false. This is pretty close, but forces me to express the transitive dependencies of the direct dependencies I do declare. This isn’t acceptable because I want the build.gradle to express all the direct dependencies and none of the indirect ones.

The only other knob I see to tweak is turning off transitive dependencies of specific dependencies. This doesn’t seem applicable though.

Any ideas?

I don’t understand the second paragraph. Can you elaborate?

In my experiment to see how this works I have a “test” source set containing Groovy tests. When I set

configurations[‘testCompile’].transitive = false

The “compileTestGroovy” task fails with ClassNotFoundException for org.hamcrest.Matcher thrown from Gradle’s TransformingClassLoader::findClass method. The “testCompile” configuration has a dependency on JUnit which itself has a dependency on Hamcrest. However, because I don’t use Hamcrest directly, I didn’t include it as a dependency. Once I do, this exception goes away and everything works again.

This is not intuitive to me. Maybe its something Groovy related, but I would not expect compilation failures for missing transitive dependencies.

In the end, I’d like to prevent Java & Groovy masking missing direct dependency declarations by successfully compiling using indirect transitive dependencies.

Either use ‘transitive = false’, or use the ‘@jar’ dependency notation. And yes, the Groovy compiler is known for sometimes needing transitive dependencies on the compile class path.

Thank you for your response. I’m to the point now where I’m not convinced what I want is possible independent of Gradle. Let me give a non-Groovy example:

Let’s say I am building project X which has a class A that extends class B which implements interface class C. All 3 classes are pure Java. Class B comes from external module Y which has a dependency on external module Z containing interface class C. So …

Class A depends on class B which depends on class C Project X depends on module Y which depends on module Z

Running javac from the command line fails when C in not the CLASSPATH and works when it is in the CLASSPATH.

It sounds like I have a fundamental misunderstanding of what Java needs at compile time versus runtime.

1 Like

In this case, javac will indeed need B and C on the class path (or source path). When not using transitive dependency resolution, you’ll have to take care of this manually.