Need 2 different versions of same dependency in Gradle - spring

I am working on a spring boot Gradle application that has a dependency on spring-ldap. The issue is, I need to use our firm's custom dependency for ldap operation which has an older spring-ldap version bundled in it: org.springframework.ldap:spring-ldap-core:1.3.0.RELEASE but the spring-boot dependency comes with the newer version: org.springframework.ldap:spring-ldap-core:2.3.3.RELEASE.
By default Gradle promotes to the newer version of the dependency but even If I force to use any one from these dependency versions, it is throwing runtime MethodNotFound exception at a different location as both dependencies have different method names which are being used by both parent dependencies.
It seems that I need both dependencies in order to run the application and use them from different parent dependencies like:
Spring boot autoconfigure -> spring-ldap-core:2.3.3.RELEASE
Firm's dependency -> spring-ldap-core:1.3.2.RELEASE
What is the best available solution for this?

Related

How to check the compatibility of transitive dependency with its direct dependency Spring Boot Maven Project

So in my organization we started to scan all our application for vurnerabilities and the scanner show up with lots of findings.
Some CVE are easy to be fix, but some require extra steps, and I wonder how to properly fix CVE in transitive dependency, expecially Spring Boot transitive dependency, since many in my application we use the spring boot starter dependency to pull all other spring framework related dependency.
For example one of my application still use Spring Boot version 2.6.2 and some of the CVE foundings include CVE-2022-22978 where I need to upgrade the spring-security-core dependency to a minimum version 5.6.9, it is better to upgrade the spring boot version to the latest 2.6.14 or just upgrade the spring-security-core dependency ? My concern on upgrading the spring boot version to the latest will somehow break my application and will cause a major change to the application.
How do we properly fix CVE issue on the transitive dependency while the direct dependency has not release their fix yet?
Is it safe just to upgrade specific transitive dependency? How do we know if the upgraded transitive dependency compatible with its direct dependency?

What is micronaut-bom?

While I worked on a Micronaut project und tried to solve some problems, like dynamic versioning of dependencies and creating a multi module micronaut project with Gradle. I found in some code examples of the build.gradle this dependency:
annotationProcessor platform("io.micronaut:micronaut-bom:2.0.0")
But I could not find any official documentation referring to it. What does it do? Can it help me with versioning my dependencies?
The Micronaut BOM (Bill Of Material, further reading) declares all the framework dependencies of a specific Micronaut release. In your example it is the BOM of Micronaut release 2.0.0.
By declaring the as a platform dependency you don't have to worry about Micronaut about the versions of supported JARs, since they already are defined in the BOM.
For example if you decide to use the Caffeine Cache with Micronaut you simply declare it as a dependency but omit the version number.
dependencies {
implementation("io.micronaut.cache:micronaut-cache-caffeine")
}
That way you make sure that you are using well tested dependencies with your Micronaut release.
why is it an `annotationProcessor?
An update since the following question came up.
Uuh. Nice. So its a collection of dependencies with the best working versions for my specific micronaut version? Cool. And why is it a annotationProcessor?
annotationProcessor is Gradle related and is called a dependency configuration. When using the java Gradle plugin you have out of the box dependency configurations such as implementation or api.
With a dependency configuration you configure the dependencies for e.g. an annotation processor by using the configuration annotationProcessor. implementation is used for your compile time dependencies. And if you want to expose the dependencies to other modules that use your module you might want to use api instead of implementation.

How to get the specific version of dependency from the spring boot starter packs

I have a project where we are using gradle:
and we have added the dependency of: implementation 'org.springframework.boot:spring-boot-starter-security:2.6.5'
This starter dependency brings the
spring-security-config:5.6.2 and
spring-security-web:5.6.2
But we need the spring-security-config and spring-security-web version to be 5.6.9 and we don't want to upgrade the starter dependency version as well.
I tried setting the ext['spring-security.version']='5.6.9'
But it didn't work.
Is there any other way we can achieve this?

What's the logic of Gradle dependency resolving

In Gradle 6.7, we have a dependencyManagement.dependencies to set the defaults for the project.
Recently, someone replaced the individual dependency lines for Spring with a dependencySet.
dependencySet(group: 'org.springframework.boot', version: "2.2.11.RELEASE") {
entry 'spring-boot-devtools'
entry 'spring-boot-dependencies'
entry 'spring-boot-devtools'
entry 'spring-boot-starter-aop'
entry 'spring-boot-starter-cache'
entry 'spring-boot-starter-webflux'
...
Now after spotting some CVE alerts, I found out that Gradle resolves spring-boot-starter-cache to 2.2.8 anyway. I am not sure where it's getting that version from: We don't have it in our project, and the deps tree appears as if we asked for it ourselves (it's at level 0).
+--- org.springframework.boot:spring-boot-starter-cache -> 2.2.8.RELEASE
When I add the item explicitly, as we had before for all,
dependency 'org.springframework.boot:spring-boot-starter-cache:2.2.11.RELEASE'
then it ends up being resolved as 2.2.11.
+--- org.springframework.boot:spring-boot-starter-cache -> 2.2.11.RELEASE
In Maven, dependency management is very straighforward, compared to this: You control it using dependency management, and BOMs, and all works, no surprises like this.
So maybe I am missing something in Gradle's logic, even after reading the dependency management guide.
How can I use BOM-like dependencySet to control all entry-es at once? Or do I have wrong assumptions?
In Gradle 6.7, we have a dependencyManagement.dependencies to set the defaults for the project.
Do not confuse Spring's dependency management Gradle plugin with Gradle's native dependency mangaement functionality. Although they achieve the same goal, they do it in very different ways.
I am not sure where it's getting that version from: We don't have it in our project, and the deps tree appears as if we asked for it ourselves (it's at level 0).
You can use the dependencyInsight task to get more information on a specific dependency and why a specific version was chosen.
./gradlew dependencyInsight --dependency org.springframework.boot:spring-boot-starter-cache
See Viewing and debugging dependencies
for more details.
How can I use BOM-like dependencySet to control all entry-es at once? Or do I have wrong assumptions?
The docs for the Spring dependency management plugin are clear what you need to do to achieve that: https://docs.spring.io/dependency-management-plugin/docs/current/reference/html/#dependency-management-configuration-dsl-dependency-sets
If it is not working as you expect, then you need to debug your dependencies as I have linked above.
Also from your examples, my guess is that you have a typical Spring Boot application with the Spring Boot Gradle plugin applied. If so, then the Spring Boot Gradle plugin detects if the Spring dependency management plugin is applied and automatically imports the Spring Boot BOM. So there should not be a need to manage Spring specific dependencies as you are.

Up to date Spring boot version in submodule & different Spring version in parent

I am trying to create the Spring Boot application which is submodule of our project's parent pom (which depends on our internal framework which locks down spring dependency versions - as of now we are at 4.2.4-RELEASE)
If I specify the latest Spring Boot version (1.4.1-RELEASE) which depends on spring 4.3.3-RELEASE, I am facing conflicts
One of them is following error:
Caused by: java.lang.NoClassDefFoundError:
org/springframework/beans/factory/ObjectProvider
This class was introduced in 4.3, which explains that error
Is there a way how to keep my Spring Boot dependencies up-to-date without updating Spring versions in internal framework?
You're supposed to keep all your Spring dependencies in sync by making spring-boot-starter-parent your parent.
That sets up all the <dependencyManagement> for you, and you should not then be using <version> when you pull in specific dependencies.
If you need to override a version managed by the parent, there should be a property that you can change, named e.g. logback.version, spring-security.version, etc.
You can also stop one of your dependencies from overriding the versions of its dependencies by using <excludes> to remove the transitive dependency entirely, and ensuring you pull it in from elsewhere. This is a much more brittle though.
You could also try importing spring-boot-dependencies into your dependencyManagement, but you're probably making more work for yourself trying to add your existing projects as the Boot project's parent, rather than as dependencies.

Resources