We’ve recently run into some issues in a Java Gradle project with conflicting netty.io versions. Our project uses gRPC (grpc.io) which brings in a transitive dependency on several netty.io libraries via io.grpc:grpc-netty. We also need io.netty:netty-codec-haproxy, which is not included by grpc-netty. Our recent upgrade to grpc-netty:1.0.3 broke our build, because it updated to 4.1.6.Final of netty.io’s core, but we still had netty-codec-haproxy on 4.1.4.Final.
Dynamic versioning won’t work here, because we don’t need the latest version; we need the one that matches whatever grpc-netty uses. Is there a way to find the version being included via transitive dependency of, say, io.netty:netty-common, and apply that version to netty-codec-haproxy?
ext {
grpcVersion = ‘1.0.3’
}
dependencies {
// Server implementation for gRPC (with native openssl)
compile “io.grpc:grpc-netty:$grpcVersion”,
“io.netty:netty-tcnative-boringssl-static:1.1.33.Fork19:${osdetector.classifier}”
Thanks, Chris, but that’s not really superior to just including the extra dependency explicitly. I still have to either examine the incoming POM for the new grpc-netty, or else let the gradle build run & see what the transitive dependency resolver brings back, and then manually copy that over to the netty-code-haproxy dependency version. I’m looking for something that reduces the number of separate human interventions necessary to maintain this build each time we update our gRPC version. It’s not just convenience - if someone forgets this step, the build won’t necessarily break in an obvious fashion, but it can become unstable in production under load (as has happened to us.) A way to make this a DRY change would prevent any recurrence of that error.
Force doesn’t solve the issue you are trying to avoid, but it does have a significantly different behaviour than just declaring an extra dependency. Declaring an extra dependency will not help in the case where some dependency in the graph happens to request a higher version of netty-code-haproxy than you want. In that case, Gradle will pick the highest requested version (as you’ve observed). If however you use force on netty-code-haproxy, it doesn’t matter what versions are in the resolved dependency graph, your specified version will be used.
I took a stab at forcing a dependency based on what is in the requested dependency tree. I think this might be something you could work from.
In my example I want to force the version of hamcrest-core used by junit, regardless of other dependencies on hamcrest-core. With just junit 1.9 and hamcrest-core 1.2 defined as dependencies, we get hamcrest-core 1.2 instead of 1.1: