Compile against top-level dependencies only

Hi. I remember reading somewhere in the gradle documentation, that my code is compiled only against the top-level dependencies (I can’t find it now!). However, it seems to be different - I have a dependency from maven central on google guice, that depends on javax.inject (so it is transitive). However, when I use the javax.inject.Inject annotation in my code, it compiles fine, although I think it shouldn’t. I actually consider it a very neat feature to only compile against first level deps and would love to see how it works out for us. Do I need to turn on something special?

I’m using gradle 1.0.

wujek

To get the desired behavior, you can do:

dependencies {

compile “com.google.inject:guice:3.0@jar”

runtime “com.google.inject:guice:3.0” // if you need transitive dependencies at runtime

}

Future versions of Gradle will improve on this. The general idea is to put the API of a dependency on the compile class path. This may be more than the dependency itself, but is, in all likelihood, less than what you get today.

Thanks for your answer.

This seems however to be a workaround with code duplication (albeit minor, but image it for each top level dep), where here in the documentation:

http://www.gradle.org/docs/current/userguide/dependency_management.html#sub:transitive_dependency_management

the very last sentence says:

“Gradle also validates your dependency hierarchy against the reality of your code by using only the first level dependencies for compiling.”

which implies this is supported out-of-the-box, which obviously isn’t true, right? The docs might need fixing.

Regards, wujek

Yes, that statement needs to be corrected. Defaulting to only first-level dependencies would be problematic because it would break various things (working with Maven dependencies and Groovy compilation at the least). But as I said, future Gradle versions will improve over what we have today.

This seems however to be a workaround with code duplication (albeit minor, but image it for each top level dep)

If you want this for many or all dependencies, you can script a solution that gets by without code duplication.

Yes, I know I can script it, it’s Groovy after all, that’s why it is so attractive.

However, I seem to have problems. I have a class that extends WebApplication (which is an Apache Wicket class), that inside has a field of type javax.servlet.ServletContext. In Java, I can compile against the Wicket jars only (servlet-api is not necessary), whereas in Groovy I get some exception about some transformer problem, and eventually, the root cause being a ClassNotFoundException: javax.servlet.ServletContext.

This means I really cannot compile against top level dependencies only with Groovy, is that what you meant? As you touched the topic, could you please shed some more light on the problem? I meant to as on the Groovy list, but asyou mentioned it, maybe you can tell more?

wujek

The Groovy compiler uses Java reflection to investigate the compile class path, which means that it potentially (depending on JVM implementation and mood) needs all runtime dependencies on the compile class path, transitively. This is something that the Groovy folks plan to fix for Groovy 2.1 or 3.0. So yes, you cannot currently compile Groovy code against first-level dependencies only.

In the case of the servlet Jar, the situation is particularly tricky. Putting servlet-api.jar on the compile class path won’t work because this Jar is designed not to be loadable by a class loader. The solution is to put an implementation Jar on the compile class path.

Hi, yes, I know the sun/oracle jars are just dummies, I would use the jars from geronimo or jboss that contain ‘real’ classes. But it’s good to know that I am not losing it, I have never thought Groovy might be doing things differently.

Thanks!

With Gradle you are never losing, only winning. :slight_smile: