Why do test scope dependencies pull compile scope dependencies in Maven? - spring

Currently my project uses spring boot starter test as so:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.3.8.RELEASE</version>
<scope>test</scope>
</dependency>
However, despite the test scope, it pulls in spring-core (which is a vulnerable tpl in this version) as a compile scope transitive dependency and it appears inside my compiled binary.
I'm aware that I can fix this by pulling spring-core explicitly with test scope:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.2.12.RELEASE</version>
<scope>test</scope>
</dependency>
However this shouldn't be necessary. Why is a dependency that's only available in tests pulling dependencies into the compile scope?

I double checked after the comment from J Fabian Meyer. While spring core was appearing under spring-boot-starter-test in the dependency tree, it was being pulled into the compile scope by spring-boot-starter-web.
My guess is spring-boot-starter-test pulls a later version of spring-core which is why it appeared in the tree as so

Related

Why is spring-boot-dependencies in dependencyManagement?

The Spring documentation Using Spring Boot without the parent POM shows that the dependency on spring-boot-dependencies is added to the dependencyManagement section. Is this really correct?
spring-boot-dependencies specifies version properties for all the dependencies. However, these properties are not available in the POM that uses spring-boot-dependencies. Presumably, this is because spring-boot-dependencies is in dependencyManagement.
spring-boot-dependencies only includes dependencyManagement and pluginManagement. So it seems possible to include spring-boot-dependencies as a dependency (not dependencyManagement) without adding unnecessary dependencies.
So why is spring-boot-dependencies to be included as dependencyManagement?
So why is spring-boot-dependencies to be included as dependencyManagement?
Let's say you have a project named projectA and you add the spring-boot-dependencies to the dependencyManagement section in your pom.xml.
<project>
<groupId>com.iovation.service</groupId>
<artifactId>projectA</artifactId>
<version>1.0.0-SNAPSHOT</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<type>pom</type>
<version>1.5.8.RELEASE</version>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- Spring Boot Dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
...
</project>
If you notice closely, you will find that all the Spring Boot dependencies declared under the dependencies section don't need to specify the version. It derives the version from the version of spring-boot-dependencies specified in the dependencyManagement section.
Advantages of Dependency Management
It centralizes dependency information by specifying the Spring Boot version at one place. It really helps during upgrade from one version to another.
Subsequent declaration of Spring Boot dependencies just mentions the library name without any version. Especially helpful in multi-module projects
It avoids mismatch of different versions of spring boot libraries in a project.
No Conflicts.
It's definitely correct. Please see Using Spring Boot without the parent POM!
First, let’s understand what dependency is. So when you are developing an application, you would probably need a number of libraries(normally jar files). It means that your application depends on these libraries. Hence the name dependency.
Now you need a way to assemble all these libraries and manage them in a centralized fashion. This also means that these libraries would be made available at compile time or runtime when needed. This is what dependency management does.
So the process of dependency management involves locating these dependencies and adding them to the classpath.
Maven is a popular dependency management tool which will centralize all dependencies information.

spring boot starter test 1.4.1 - use assertj-core 3.5.x

I want to use the latest assertj-core for Java8 (for example to assert on optionals).
I use spring-boot-starter-test 1.4.1 it comes with assertj 2.5.0 preconfigured.
I cannot use a spring boot parent pom.
How can I set up my maven project, so I exclude or overwrite version 2.5.0 with 3.5.2? I tried
setting just the property assertj.version
adding exclusions on the starter-test dependency
adding exclusion on the spring-boot-dependencies
Update:
I am setting up a custom "test" module for all modules in my multi module project. I do not just need spring-test-starter but also some other dependencies and some test classes and rules.
This is what my project looks like:
my-module-root
|-my-module-a (using test)
|-my-module-b (using test)
\-test (including starter-test, ... - in COMPILE scope (because this is a test library))
Now, when I exclude assertj-core on the test module (and include 3.5.2), the dependencies for the test module are ok.
But when I check the dependencies on the root level, I have both, assertj-core-2.5.0 and assertj-core-3.5.2 on the classpath.
You can exclude it from spring-boot-starter-test and then add manually different version:
<dependencies>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.5.2</version>
<scope>test</scope>
</dependency>
</dependencies>
To verify which version is included:
$ mvn dependency:tree | grep assertj
[INFO] \- org.assertj:assertj-core:jar:3.5.2:test

maven spring library correct dependency

Let's say I am creating a new project, maven based, and I want to use spring 4.2.3.RELEASE.
I also want to use spring-test and spring security and X, Y and Z.
How can I know for sure what exact versions to add in maven to avoid conflicts?
Thanks
later edit:
can this help me?
Maven "Bill Of Materials" Dependency
It is possible to accidentally mix different versions of Spring JARs when using Maven. For example, you may find that a third-party library, or another Spring project, pulls in a transitive dependency to an older release. If you forget to explicitly declare a direct dependency yourself, all sorts of unexpected issues can arise.
To overcome such problems Maven supports the concept of a "bill of materials" (BOM) dependency. You can import the spring-framework-bom in your dependencyManagement section to ensure that all spring dependencies (both direct and transitive) are at the same version.
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>4.2.3.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
An added benefit of using the BOM is that you no longer need to specify the <version> attribute when depending on Spring Framework artifacts:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependencies>
You are right, the BOM is one of the most powerfull ways to fight (even maven based) dependency hell.

Maven 2 effective dependancies runtime and compile scope

What happen if I have in effective pom same dependency, but with different scopes: runtime and compile.?
For example,
<dependency>
<groupId>my_dep</groupId>
<artifactId>My_dep_subdata</artifactId>
<version>0.0.2</version>
<scope>runtime</scope>
</dependency>
....
<dependency>
<groupId>my_dep</groupId>
<artifactId>My_dep_subdata</artifactId>
<version>0.0.2</version>
<scope>compile</scope>
</dependency>
Which one will take place?
compile is available in all classpaths.
runtime is available in the runtime and test classpaths, but not the compile classpath.
I'd assume you will have the dependency on all classpaths (as in compile), but I have no idea why you would do something like that.

Maven test dependencies: how to get dependencies from sibling project into test scope of dependent project

I have a multi-module maven project with the structure
main/
core/
interface/
where interface has a dependency on the artifact produced by core.
interface compiles, packages, and installs properly. However, when running tests in interface they fail due to not resolving dependencies found in core.
interface does not depend on the test classes themselves in core, simply compile scope maven dependencies defined in the core pom.xml file.
I did one painful attempt whereby I copied every single compile dependency declaration in core that was needed into the interface pom.xml and gave them all
<scope>test</scope>
. This helped with the tests but broke the install.
What is the best way to fix the dependency resolution of these tests in interface?
Here is an example of compile scope dependencies that are not resolved when running interface maven test goal.
core/pom.xml excerpt:
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-api</artifactId>
<version>${jsf-version}</version>
</dependency>
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-impl</artifactId>
<version>${jsf-version}</version>
</dependency>
interface/pom.xml excerpt:
<dependency>
<groupId>com.mycompany</groupId>
<artifactId>core</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>

Resources