spring-boot dependency override : dependency upgrade best practices? - spring

is it safe to override spring-boot dependencies in applications?
spring-boot 2.3.0.RELEASE supports apache httpclient(4.5.12).
will it be safe to override in my application with apache client version 4.5.13? is there any other best options in upgrading spring-boot dependencies?
spring-boot dependencies project : https://github.com/spring-projects/spring-boot/blob/v2.3.0.RELEASE/spring-boot-project/spring-boot-dependencies/build.gradle

if you are using spring-boot-dependencies to resolve dependencies then one easy way to put your newer version artifact ahead of the spring-boot-dependencies definition and make sure they are part of the parent pom if you have further child poms.

Related

Need 2 different versions of same dependency in Gradle

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?

Need to know the difference between spring-boot-starter-parent and spring-boot-parent

Can some one explain me the difference between spring-boot-parent and spring-boot-starter-parent, As i have seen in one of the GIT HUB code link attached below where they have written separate modules for spring-boot-starter-parent and spring-boot-parent.
https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/
If any one knows the difference between these two dependencies pls let me know, Also in most of the projects we generally use spring-boot-starter-parent as parent but not spring-boot-parent when both of them shares the same parent spring-boot-dependencies.
https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/
As described at https://www.baeldung.com/spring-boot-starter-parent
Spring-boot-starter-parent
The spring-boot-starter-parent project is a special starter project –
that provides default configurations for our application and a
complete dependency tree to quickly build our Spring Boot project.
It also provides default configuration for Maven plugins such as
maven-failsafe-plugin, maven-jar-plugin, maven-surefire-plugin,
maven-war-plugin.
Beyond that, it also inherits dependency management from
spring-boot-dependencies which is the parent to the
spring-boot-starter-parent.
spring-boot-parent
Sometimes we have a custom Maven parent. Or, we may prefer to declare
all our Maven configurations manually.
In that case, we may opt to not use the spring-boot-starter-parent
project. But, we can still benefit from its dependency tree by adding
a dependency spring-boot-dependencies in our project in import scope.
Spring Boot Starter Parent helps us with managing dependency versions, the java version used by project and the default configuration for plug-ins, as we don't have to specify a lot of things manually.
It helps us with the following :
Configuration
Dependency management
Default plugin configuration (default configurations for maven-failsafe-plugin, maven-jar-plugin and maven-surefire-plugin etc)
According to spring-boot doc :
Starters are a set of convenient dependency descriptors that you can
include in your application. You get a one-stop shop for all the
Spring and related technologies that you need without having to hunt
through sample code and copy-paste loads of dependency descriptors
The spring-boot-starter is the Core starter and provides functionalities including auto-configuration support, logging and YAML.It defines spring-boot-dependencies as the parent pom .
In the github url that you provided , they have kept a separate module to specify the parent spring-boot-dependencies in the pom.It might be because they needed to use the spring-boot-dependencies , dependency tree alone without the auto-configuration and plugin configuration , and publish it as separate jar for some use-case.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${revision}</version>
<relativePath>../spring-boot-dependencies</relativePath>
</parent>
https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-parent/2.1.6.RELEASE
I believe you meant the difference between spring-boot-starter-parent and spring-boot-starter.
spring-boot-starter-parent - has spring-boot-dependencies as the parent and hence provides various spring-boot dependencies and helps in dependency management. In addition to this spring-boot-starter-parent on it's own helps in plugin management as well.
So if you use only spring-boot-dependencies you can benefit from the dependency management provided by it but instead if you use the spring-boot-starter-parent, you get dependency management + plugin management.
spring-boot-starter - It is a dependency provided by spring-boot-dependencies which provides dependencies for autoconfigure, logging and also spring-core. In order to pull any dependency from the starter or from spring-boot-dependencies, you need to explicitly add it as a dependency in your main pom.

Gradle 5 JUnit BOM and Spring Boot Incorrect Versions

I am using Gradle 5's BOM (Bill of Materials) feature. This is how I describe it for my JUnit 5 dependencies:
testImplementation(enforcedPlatform("org.junit:junit-bom:5.4.0")) // JUnit 5 BOM
testImplementation("org.junit.jupiter:junit-jupiter-api")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
testImplementation("org.junit.jupiter:junit-jupiter-params")
My assumption is that providing the BOM will resolve the versions of the dependencies to 5.4.0. However, they get resolved to 5.1.1. I am not sure why. (I also request enforcedPlatform() to lock the specified version)
Inspecting JUnit 5's BOM we see that all org.junit.jupiter dependencies are listed with version 5.4.0 (resolving to 5.1.1 in the project) and all org.junit.platform dependencies are listed with version 1.4.0 which resolve correctly in the project.
I am not sure what I am missing and was hoping to get some help here. Thanks!
EDIT:
I used Sormuras response and moved all BOMs at the top of the dependencies {} block but was still not getting version 5.4.0. Then I suspected it might be coming from the Gradle Spring Dependency Management plugin that I use, so when I commented it out, I got version JUnit 5.4.0. How do I disable JUnit coming from the Gradle Spring Dependency Management plugin?
FINALLY:
I decided to use the Spring Boot Dependencies BOM directly and remove the Gradle plugin:
implementation(platform("org.springframework.boot:spring-boot-dependencies:2.0.5.RELEASE"))
I imagine the plugin was created for those version of Gradle before Gradle 5 where you couldn't use a BOM file. Now with the BOM support I can directly include it. This way my version of JUnit is as I have specified it in the enforcedPlatform() block.
I accepted Sam Brannen's answer below because he explains well how the issue occurs and what solves it and I think it's relevant for those who use older versions of Gradle.
How do I disable JUnit coming from the Gradle Spring Dependency Management plugin?
For starters, if you are using the dependency management plugin from Spring, you should not be importing the junit-bom since that results in duplicate (and potentially conflicting) management of those dependencies.
Aside from that, whenever you use the dependency management plugin from Spring and want to override a managed version, you have to do it by overriding the exact name of the version defined in the BOM used by the plugin.
This is documented in Spring Boot for Gradle and for Maven.
For Spring Boot the name of the JUnit Jupiter version is "junit-jupiter.version". You can find the names of all managed versions for Spring Boot 2.1.2 here.
So, in Gradle you would override it as follows.
ext['junit-jupiter.version'] = '5.4.0'.
You can see that I have done exactly that here.
With Maven you would override it as follows.
<properties>
<junit-jupiter.version>5.4.0</junit-jupiter.version>
</properties>
Further background information here: https://docs.spring.io/platform/docs/current/reference/html/getting-started-overriding-versions.html
JUnit 5.4.0 simplified its artifacts, and now delivered a single artifact for Jupiter - org.junit:junit-jupiter. I.e., you should simplify your Gradle file too:
testImplementation(enforcedPlatform("org.junit:junit-bom:5.4.0")) // JUnit 5 BOM
testImplementation("org.junit.jupiter:junit-jupiter")
Ensure to include JUnit's BOM before other BOMs that also refer to JUnit. First BOM wins and locks version of all later artifacts.
See this issue for a similar setup using Maven and Spring Boot: https://github.com/sormuras/junit-platform-maven-plugin/issues/29#issuecomment-456958188

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.

Maven: How to include a dependency with a specific build profile?

I have a project where I use Spring Boot 1.1.2.RELEASE which uses Spring 4.1.5, and Spring HATEOAS 0.10.0.RELEASE which uses Spring 4.0.9. This causes some dependency problems like the infamous java.lang.ClassNotFoundException: org.springframework.beans.factory.SmartInitializingSingleton.
I dug into the POM of spring-hateoas and found that there are different profiles defined, one of them being spring41 which depends on Spring 4.1.5. Is it possible to select this profile in my <dependency> section, or do I have to exclude the Spring dependencies?
Automatically selecting a profile for a build isn't easy. You can enable it by default in your personal settings.xml but that breaks the build for everyone who doesn't have the same file.
You can't enable a profile in the POM of the project.
With Maven 3.3, you can add the profile to ${maven.projectBasedir}/.mvn/maven.config. Since this file is part of the project, it's easy to share. You can use the Maven Enforcer plugin to make sure everyone uses a Maven version with actually uses the file.
If you can't use 3.3, then your best bet is to exclude the dependencies. If you have a parent POM, then you can use a dependencyManagement element to do it for all POMs in the reactor build.

Resources