Require Direct Dependency Declarations at Compile Time

(Mark Maxey) #1

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?

(Peter Niederwieser) #2

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

(Mark Maxey) #3

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.

(Peter Niederwieser) #4

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.

(Mark Maxey) #5

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.

(Peter Niederwieser) #6

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.