JUnit5 (aggregator) provides old dependencies [duplicate] - java

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

Related

Maven fetching incorrect dependencies [duplicate]

I tried to migrate gradle project with spring boot from selenium 3 to selenium 4
(implementation 'org.seleniumhq.selenium:selenium-java:4.1.1')
But chrome, firefox and edge web drivers remains from selenium version 3
(org.seleniumhq.selenium:selenium-chrome-driver:3.141.59).
If I remove spring boot dependency from project, they updates to 4.1.1
Currently using gradle version "7.3.3".
Spring boot "2.6.3".
Spring dependency management "1.0.11.RELEASE".
Any ideas why this happens, I hoped that dependency hell dissapeared with spring boot creation)
Thanks in advance!
I have the same promble, I found in spring-boot-starter-parent, there is a spring-boot-dependencies in ~/.m2/repository/org/springframework/boot/spring-boot-dependencies/2.6.3/spring-boot-dependencies-2.6.3.pom, which declared <selenium.version>3.141.59</selenium.version> in properties, so you can try add
<properties>
<selenium.version>4.1.2</selenium.version>
</properties>
in your project pom.xml.
Spring Boot comes with a set of versions that are know to work together. But you can override them in your build script. In case of Gradle, add to build.gradle:
ext['selenium.version'] = '4.1.2'
It is because Spring Boot comes packed with a set of predefined dependecies that you can find here: https://docs.spring.io/spring-boot/docs/2.6.7/reference/htmlsingle/#appendix.dependency-versions
In this page, you will also find, how to change predefined version. In general, you need to add .version to your dependency name and, in case of multiple word names, you change spaces to dashes (not needed in case of selenium).
So, to change version to most recent, type in build.gradle ext['selenium.version'] = '4.4.0' at 0 indent level. (don't add it, say inside dependencies {})

Define Spring dependency matching a Spring Boot version

I am developing two projects.
Project 1 is a spring-boot application based on gradle for dependency management. This application defines extension-points. If - at runtime - an extension is found on the classpath, this extension is being called from the main application under certain circumstances.
Project 2 is such an extension. This extension should only provide low-level functionality. So basically, I need spring annotations and an EntityManager within the application but I would like to prevent the full spring-boot dependencies to be present on the compile-path.
The obvious (and not satisfactory) solution is to define a compileonly-dependency on a specific version of, say, spring-context. This is somewhat dangerous, as the spring-boot version may progress and it may be easy to forget to adjust the spring version.
Providing a compileOnly dependency to spring-boot-starter (or even the main project) is out of the question.
So, is there a clever trick to tell gralde to use "the spring-version coming with spring-boot-xxx"?
Sometimes you are within a forrest and not seeing the trees...
Thanks to the comment of #emrekgn I looked for BOM/Gradle/Spring and found... the spring boot dependency-management plugin.
Adding this to your gradle file will allow you to include dependencies matching to the spring boot version you are using:
plugins {
id 'org.springframework.boot' version '2.6.2'
}
apply plugin: 'io.spring.dependency-management'
Obviously, you have to match the boot-version to your needs.

how to choose between versions in build.gradle

if you have a build.gradle file with the line implementation 'org.springframework.boot:spring-boot-starter-web', how do you choose the version of the jar it downloads so that you get the latest one? I've seen a project where it is a 2.2.4 release, but in another project I've seen the same line with a 2.2.5 release.
Since you dropped the name Spring Boot, I assume the project has been generated Spring Initializr. A project generated with the Initializr has two plugins applied:
org.springframework.boot (Reference Documentation)
io.spring.dependency-management (Reference Documentation)
io.spring.dependency-management is Spring's opinionated way to provide Maven-like dependency management to Gradle builds. It allows to declare dependency versions once and then omit the version when declaring the actual dependency.
The org.springframework.boot plugin does the following:
When you apply the io.spring.dependency-management plugin, Spring Boot’s plugin will automatically import the spring-boot-dependencies bom from the version of Spring Boot that you are using. This provides a similar dependency management experience to the one that’s enjoyed by Maven users. For example, it allows you to omit version numbers when declaring dependencies that are managed in the bom. To make use of this functionality, simply declare dependencies in the usual way but omit the version number.
(From: Managing Dependencies)
What does that mean in practice?
When you generate a project for Spring Boot 2.1.14, your build.gradle will look similar to this:
plugins {
id 'org.springframework.boot' version '2.1.14.RELEASE'
id 'io.spring.dependency-management' version '1.0.9.RELEASE'
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
}
The org.springframework.boot plugin instructs the io.spring.dependency-management to apply the bill of materials (BOM) of Spring Boot 2.1.14. The BOM declares the following version for spring-boot-starter-web:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.14.RELEASE</version>
</dependency>
(From: Maven Central)
And this combination allows to declare the dependency to spring-boot-starter-web in the build.gradle without providing an actual version:
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
}
If you would change the version of the org.springframework.boot Gradle plugin, then a different version that matches the Spring Boot versions would be applied.
You may ask, why this tremendous effort?
We take an opinionated view of the Spring platform and third-party libraries so you can get started with minimum fuss.
That's why.
One possible solution is to use lockfiles and a version of +, or a combination of major.minor.+ or major.+
implementation 'org.springframework.boot:spring-boot-starter-web:+'
For more information on dependency locking: https://docs.gradle.org/current/userguide/dependency_locking.html
Another approach, and one I'm quite pleased with where available, is using a bill of materials, which specifies versions for a lot of dependencies, by introducing constraints. So where a dependency is used, with no version specified, as in your example, it will get the version the BOM brings in. So for the dependency below, if it is present in the BOM, it will match
implementation 'org.springframework.boot:spring-boot-starter-web
You're also free to override versions manually, by still specifying the version, should you choose to. And a BOM is like any other dependency, so you can use a mixture of lockfiles and BOMs.
Here's gradle documentation on bill of materials: https://docs.gradle.org/current/userguide/platforms.html

Maven dependency with older spring boot version

Is it somehow possible to use Maven dependency with older Spring Boot version? The project is using version 2.x and the custom dependency uses 1.5.x.
Could not found any documentation on the topic.
I'm asking because of getting a NoClassDefFoundError while introspecting class inside the custom jar file.
No. Spring Boot 2.X is a major version which is not backwards compatible with Spring Boot 1.5.X. Same goes for major Spring Framework versions, you can't mix Spring Framework 5.X and 4.X.
Maven only manages project dependencies. It has nothing to do with your problem.
Basically there can only be one version of any given combination of groupId and artifactId in any maven project. So with plain vanilla maven, the answer is 'No'. But there is the maven-shade-plugin that can be used to change the group- and artifact ids of any dependency.

Is there any replacement of dependencyManagement.importedProperties in Gradle 5?

I need to get a property like "jackson.version" from a BOM similar to org.springframework.boot.spring-boot-dependencies. I know I can do this with io.spring.dependency-management plugin by using dependencyManagement.importedProperties. But what is a way to this with Gradle's 5 Maven BOM support?
This is an example with io.spring.dependency-management(Kotlin DSL):
dependencyManagement {
imports {
mavenBom("org.springframework.cloud:spring-cloud-dependencies:Greenwich.RELEASE")
}
}
dependencies {
implementation("org.group:artifact:${dependencyManagement.importedProperties["spring-cloud-aws.version"]}")
}
I'd like to do the same with Gradle 5:
dependencies {
implementation(platform("org.springframework.cloud:spring-cloud-dependencies:Greenwich.RELEASE}"))
implementation("org.group:artifact:${?["spring-cloud-aws.version"]}")
}
How to get "spring-cloud-aws.version"(any property from the BOM)?
Currently no. There are many features that are not yet available. You can plan to see it implemented in later versions of Gradle or more likely an equivalent functionality.
See this detailed video below on the comparison of Spring Dependency management and Gradle 5's support for importing BOMs:
Managing Dependencies for Spring Projects with Gradle by Jenn Strater and Andy Wilkinson

Categories