how to exclude gradle dependencies - spring

I currently have a project that I have performed an aqua scan on, and it identified the jackson-databind-2.9.8.jar I'm currently using as a critical vulnerability, and has recommended me to replace with version 2.10. To update this, while ensuring all other dependencies/code works fine, I've tried the following code in my build.gradle file, where group_name:microservice-event:0.2.+ shows up on the list of gradle dependencies and apparently brings in the 2.9.8 jar that is causing problems:
implementation 'com.fasterxml.jackson.core:jackson-databind:2.10'
implementation('*group_name*:microservice-event:0.2.+') {
exclude group: 'com.fasterxml.jackson.core', module: 'jackson-databind'
}
I've also removed the implementation '*group_name*:microservice-event:0.2.+' line I previously had in my build.gradle file.
However, now the project fails to build and I have no idea why. Would anyone know of how to write code in the build.gradle file to successfully exclude old jars/dependencies, while allowing for newer jars (as I've tried to do with the line implementation 'com.fasterxml.jackson.core:jackson-databind:2.10'). Note that I do not want to update the spring boot version.

When Gradle encounters two different versions of the same dependency, it will perform a conflict resolution. It defaults to choosing the highest version number.
However, because many libraries like Jackson consists of a number of individual modules like jackson-databind and jackson-core, you may end up in a situation where there is a mismatch between the different versions.
To align them, you can use the Jackson BOM and Gradle's platform dependency mechanism. It looks like this (choose only one of the depencendies below):
dependencies {
// Enforce the specified version
implementation(enforcedPlatform("com.fasterxml.jackson:jackson-bom:2.10.4"))
// Align all modules to the same version, but allow upgrade to a higher version
implementation(platform("com.fasterxml.jackson:jackson-bom:2.10.4"))
}
You don't need to exclude anything from your other dependencies.
If you encounter problems with the use of Jackson after upgrading, you should have a look at the release notes for 2.10 and check if you might be hit by any of the compatibility changes. Of cause, if the problem is in a third-party library, it might be more difficult to fix. But you may try the latest version in the 2.9 line (which is 2.9.10 at this time) and see if the vulnerability is fixed here.

Related

Gradle dependency library updated by another library

My gradle has for some time had a dependency on the (amazing) Android library Picasso. It has always been set to version 2.5.2
implementation 'com.squareup.picasso:picasso:2.5.2'
I recently updated all my Firebase libraries from a fairly old version to the latest. At which point something odd happened.
My Picasso method calls began to error
Picasso.with(context)
Which I know from this SO article results from a change to Picasso.
cannot find symbol method with() using picasso library android and I need to change to
Picasso.get()
OK not a big deal, but it got me wondering. Obviously Firebase uses the latest version of Picasso and is making my project use the latest version as well. My question is why is my local gradle file ignored and the newer version of Picasso defaulted to?
Off the top of my head: Since you declare a specific version that requirement is not flexible. To allow for a newer version if available a + declaration is required. My guess is that another dependency is also dependent on Picasso after the updates. Gradle, when given a redundant dependency, will select the newer version.
This is in alignment with what you said, if I understand correctly. If Firebase uses a newer Picasso version, because it requires that version, then Gradle is given two versions to choose one from. This will always result in the newer version being chosen. At least this is default behavior afaik.
It seems to me that you already know Picasso is used by Firebase. If you want to see where which dependency comes from however, you can look into build scans:
gradle build --scan
https://scans.gradle.com/?_ga=2.166196030.1236003146.1565212874-222812074.1565212874
A little bit more advanced dependency management:
1) Set Gradle behavior on dependency conflict:
https://docs.gradle.org/current/dsl/org.gradle.api.artifacts.ResolutionStrategy.html
2) Declare version constraints (see Rich version declaration):
https://docs.gradle.org/current/userguide/declaring_dependencies.html
You can check the official doc:
Gradle resolves version conflicts by picking the highest version of a module. Build scans and the dependency insight report are immensely helpful in identifying why a specific version was selected.

Same Gradle files, same code base, different dependency graphs for different developers

This problem seems like a real mystery to me. We are working on a Spring REST app. On my team, we have Jenkins running a build on all checkins (CI build). In addition, there is an official build done elsehwere nightly. Some integration tests recently started failing during the CI build, and we traced the cause to jar conflicts. However, we had successfully excluded the transitive dependencies that caused those conflicts earlier, and for the official build, and for some developers on the team, that is still true. For others it no longer is.
We have the same code base, and the same Gradle files. When I run the dependency task on my system, I have a long tree of transitive dependencies in one subproject (as does the Jenkins machine), whereas others have no such tree. In addition, the size of the WAR is several orders larger for some developers than for others. The transitive dependencies come from another related project uploaded to Nexus.
I have refreshed dependencies both on my machine and the Jenkins machine, and even wiped out .gradle, but to no avail.
It sounds like something environmental, but the Gradle versions and Java versions are all roughly the same, a couple minor versions off at most.
Any ideas about what could cause this discrepancy?
You could force your dependencies to specific versions across the board
def gsonModule = 'com.google.code.gson:gson'
configurations.all {
resolutionStrategy {
// add dependency substitution rules
dependencySubstitution {
substitute module(gsonModule) with module("$gsonModule:2.6.1")
}
}
}
// note: configurations block must be above the dependencies
// or build will error
dependencies {
compile "$gsonModule:2.7"
}
Then when any developer/CI/test/CD runs the build your resolutionStrategy forces consistency across all compilations. Default behavior in gradle is upon version conflict the newer version will be used. This will force the all versions to the same regardless of their declared version.
$ ./gradlew dependencies --configuration compile -q
------------------------------------------------------------
Root project
------------------------------------------------------------
compile - Dependencies for source set 'main'.
\--- com.google.code.gson:gson:2.7 -> 2.6.1
Reference: https://docs.gradle.org/current/dsl/org.gradle.api.artifacts.ResolutionStrategy.html
You should use gradle wrapper to ensure the same gradle version throughout, in order to exclude some possibility of that being a factor.
Also, add --refresh-dependencies to the gradle command-line. It may be that some of your dependencies are not being versioned correctly, and this flag will verify each time that only the latest are pulled.
Finally, take a look at workstations that have different results, and ensure that you have identical gradle.properties in your gradle user home folder and the project folder.
First, thanks for the quick responses, but I have an update:
In short, one of my colleagues identified one of the problems. I can't get into details, but the gradle files have convenience functions for either downloading another project from Nexus (such as the related project that I referred to above) or using a locally-built artifact if it exists.
Doing the latter resolves the issue. Downloading from Nexus (as Jenkins did, and as you should be able to do) allows the issue to occur, exposing it. I don't believe this effects the build order, but it does effect the transitive dependencies that are pulled in.
There are also some problems in the dependencies of the various sub-projects: e.g., one project intended not to have dependencies has one, and that one is a big culprit in bringing transitive dependencies. So when that base project is pulled in by other projects, it has ripple effects. And some of those dependency blocks need to be cleaned up.
Again, thanks for the responses!

Why did a specific jar file get included?

I have a project that uses gradle and mavenCentral() (plus mavenLocal()). It has enough dependencies that I can't go through them one by one.
Given the name of a .jar file in build/install/x/lib, how do I find out the chain of transitive dependencies that caused it to be included?
update: I discovered gradle dependencies. The output shows:
org.apache.commons:commons-jexl:2.1.1
\---- commons-logging:commons-logging:1.1.1 -> 1.1.3
What does this mean? 1.1.1 is the version I expect, and 1.1.3 is the version I seem to actually end up using. Looking at the pom for commons-jexl it looks like it does indeed list logging:1.1.1 as a requirement. What's going on? Is there a way for me to tell it to avoid certain versions, or force it to use the version it was set to?
The problem in my case is that it's including a -SNAPSHOT version and I'd rather it didn't. In fact I probably want it to just use the version numbers I'm asking for instead of the most recent it can find.
Dependencies of gradle-managed project have their own dependencies (they're called transitive). It may happen (and happens quite often) that two different dependencies has the same (group and module) dependency but in the different version). This is the case with commons-logging:commons-logging. In this case there are two transitive dependencies one versioned with 1.1.1 and the second one with 1.1.3. If both of the libraries will be included in the final artifact it may result in a conflict and exception. To prevent such situation gradle tries to resolve mentioned version resolution problems by picking (by default) the latest version. It's indicated with the right arrow -> see here. You can exclude transitive dependencies from a particular dependency. This chapter of manual might be useful.

Grails 2.4 transitive plugin dependencies don't respect the 'exclude' directive

We're currently developing a Grails plugin that is meant to be a shared library of goodies for several different applications. This plug-in does the management around GORM and caching and, as such, it includes both the hibernate plug-in and the cache and cache-ehcache plugins. Hibernate and cache-ehcache plug-ins both want to import the ehcache-core jar dependency, but with different versions. The version of ehcache-core that I want is the one in the cache-ehcache plug-in so I've configured my BuildConfig.groovy like so:
compile(':hibernate:3.6.10.10', { excludes 'ehcache-core' })
compile ':cache:1.1.8'
compile ":cache-ehcache:1.0.4"
When running tests in this plug-in everything works just fine. However, once I include this plug-in in one of my real applications the excludes directive seems to be ignored and the transitive dependency on the hibernate plug-in starts pulling in ehcache-core. Having two versions of ehcache-core breaks many different aspects.
I've checked the grails dependency-report for my applications and it shows the chain of dependencies from my app -> my utility plugin -> hibernate plugin -> ehcache-core intact. The same dependency report run on the plug-in itself just points to the hibernate plug-in and then stops with no dependency on ehcache-core.
Anyone out there have any ideas as to why the dependency exclusion works while running the plug-in, but not while running the application that depends on the plug-in?
This is due to the change to the Maven/Aether dependency manager library. It's somewhat less buggy than Ivy and significantly faster, but is missing a lot of features that many of us are used to. One easy fix is to switch back to the Ivy resolver. You would only need to do that for the plugings when publishing, but not necessarily when using them since you need a defailed .pom file with exclusions listed so the consuming dependency manager knows what to ignore. If you use Aether the .pom files only include dependencies.
EDIT: I was focusing on the correctness of the pom files, and or course exclusions like this should work (although it'd be better to have correct poms and not have to force every user to fix this on their end.)
The issue might be that your group or name are different (e.g, "cache" vs. "ehcache"), and then they cant evict/exclude another. Or the jar might be coming from a different dependency and they exclusions are not global. There may be a way to set a global exclusion, but I don't know of one and there's nothing in the docs.

Multiple versions of library with Gradle

I have the problem that Gradle is pulling in two versions of a library, which is causing runtime issues. These versions are both necessary, and are dependencies of two of the dependencies I have. Library A needs Library C version x, and Library B needs Library C version y. At runtime, the incorrect version of Library C is used, causing a NoSuchFieldError. Is this something I can resolve in Gradle? Or is it more of an issue for my IDE/JVM options?
In general Gradle will do the right thing by choosing the latest version of a library when there are dependency conflicts. However for various reasons this may not always work correctly. To get around this you can tell Gradle explicitly to not include a certain transitive dependency during its resolution. Here is an example:
compile (group:'com.project', name:'library', version:'1.0') {
// These lines will exclude these other libraries from being included
exclude module: 'groovy-all'
exclude module: 'log4j'
exclude module: 'commons-lang'
}
You can make this more fine grained if you need to, but I've found excluding modules seems to work well for me.

Resources