custom parent pom with org.springframework.cloud and spring-boot-starter-parent - maven

I have couple of spring cloud projects and wish to put all common dependencies into my own parent pom too. Many samples shows how to do it with <dependencyManagement>. But in my case with spring-boot-starter-parent and org.springframework.cloud, it seems to be not working using dependency management as the parent has already become 'spring-boot-starter-parent' and dependency management is also there having org.springframework.cloud. Following is one of my spring cloud projects' pom files.
<groupId>com.demo</groupId>
<artifactId>demo-customer-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>demo-customer-service</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath />
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
as above, there are two parents: org.springframework.boot starter parent and cloud. So how can I have my own parent ?
Any suggestion please how the parent and the child pom files should be ?

The pom you provided can perfeclty become a parent pom. Parent poms can have parent's themself also. It is commonly used and if you check the projects you are using on github they have chain of parents.
For example spring-cloud-build-dependencies has spring-boot-dependencies as parent. spring-boot-dependencies has spring-boot-build as parent.
Inside your parent pom, dependencies defined inside <dependencies></dependencies> will be added to all the childs of your parent. If all your childs are using these dependencies you can add them in this tag. (I generally add unit test dependencies here, but you can add anything)
Parent poms usualy located one folder above of childs pom.xml. (But <relativePath> can be used if it is elsewhere)
|-parent pom.xml
|-child project folder
|--child pom.xml

Related

How to force maven dependency version via dependencyManagement in parent pom?

Let's say B:1.0.1 has transitive dependency A:1.0.1, but the child project is supposed to depend on A:1.0.2 (with intentional overriding transitive dependencies).
It is easy to discover that the order of dependencies in <dependencyManagement> affect versions overriding, so adding A:1.0.2 in the child pom just before B:1.0.1 would force using A:1.0.2 even as a dependency for B:1.0.1.
In this case I'm looking for a way to declare A:1.0.2 in the parent pom, and remove boilerplate from all its children. Unfortunately, the following setup leads to using both versions in the final artifact: A:1.0.1 (comes as a dependency of B:1.0.1) and A:1.0.2 (comes from the explicit declaration in the parent pom).
How to force using version A:1.0.2 in all child projects, keeping the declaration in the parent?
Parent pom:
<groupId>my-group</groupId>
<artifactId>my-parent</artifactId>
<version>0.0.1</version>
<packaging>pom</packaging>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>g</groupId>
<artifactId>A</artifactId>
<version>1.0.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Child pom:
<parent>
<groupId>my-group</groupId>
<artifactId>my-parent</artifactId>
<version>0.0.1</version>
</parent>
<artifactId>my-child</artifactId>
<version>0.0.1</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>g</groupId>
<artifactId>A</artifactId>
<!-- version 1.0.2 comes from the parent pom -->
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>g</groupId>
<artifactId>B</artifactId>
<version>1.0.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
You are using the dependencyManagement incorrectly.
If A and B are jar artifacts, you should not have the tags
<type>pom</type>
<scope>import</scope>
These are for BOMs only.

Maven doesn't run unit tests in a multi-module project with Spring Boot

Maven supports multi-module applications by having the child modules point to the parent module, but Spring Boot wants it's parent to be
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
According to the Spring docs I can still do this (use a maven parent-child relationship) if I add dependency management like this:
<dependencyManagement>
<dependencies>
<dependency>
<!-- Import dependency management from Spring Boot -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.2.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
instead of the Spring Boot parent.
I've done this, but now my unit tests don't run when I run mvn from the command line. The unit tests still work from Intellij, but something in the new parent-child / changes is confusing mvn and keeping it from running tests.
Here's a pom.xml from a module that no longer runs its tests:
<project xmlns=...>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>abcd</groupId>
<artifactId>abcd.parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>entities</artifactId>
<name>entities</name>
<description>Entities and Repositories</description>
<properties>
<maven.compiler.target>11</maven.compiler.target>
<maven.compiler.source>11</maven.compiler.source>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<!-- Import dependency management from Spring Boot -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.2.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
This module is a library module that does not contain a #SpringBootApplication but the tests ran before converting to the maven parent-child structure.
Edit:
This project has both junit 4 and junit-jupiter-api 5.5.2 in its dependencies. When using org.junit.jupiter.api.Test (5.5.2) no tests run. When using org.junit.Test (4.12) the test runs but the Autowired repository doesn't get injected (null). (The Autowired repository is in another module.)
Spring doesn't handle dependencies correctly when using a normal maven child-parent structure.

Missing artifact org.springframework.boot:spring-boot-starter-parent:jar:1.3.2.RELEASE

I am getting the following error in POM.xml for spring boot dependency.
Missing artifact org.springframework.boot:spring-boot-starter-parent:jar:1.3.2.RELEASE
I tried all the solutions given in the following link but nothing solved my problem:
Maven2: Missing artifact but jars are in place
You're getting this error because there is no jar artifact for spring-boot-starter-parent in maven central, since spring-boot-starter-parent uses pom packaging. The reason for that is because it's intended to be used as a parent pom:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.2.RELEASE</version>
</parent>
Alternatively, you can just import the managed dependencies if that is what you intended to do:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.2.RELEASE</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
You can read more about importing dependencies in the Importing Dependencies section of the Introduction to the Dependency Mechanism article.

Should you use the parent if you are using the spring platform bom?

Some dependency versions are not in so I've added the spring platform BOM, is the parent declaration still useful?
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.1.RELEASE</version>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.spring.platform</groupId>
<artifactId>platform-bom</artifactId>
<version>1.1.1.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
I personally prefer to use platform-bom as a parent, i.e.
<parent>
<groupId>io.spring.platform</groupId>
<artifactId>platform-bom</artifactId>
<version>1.1.1.RELEASE</version>
<relativePath />
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
In this way I don't have to define spring-boot version number and it is automatically updated with newer version of spring platform and I don't have to worry about any inconsistencies.
See http://docs.spring.io/platform/docs/1.1.1.RELEASE/reference/htmlsingle/#appendix-dependency-versions for complete list of all managed dependencies.
EDIT: As pointed out by Andy Wilkinson, spring platform inherits spring-boot-starter-parent so all "sensible defaults" as described in http://docs.spring.io/spring-boot/docs/1.2.1.RELEASE/reference/htmlsingle/#using-boot-maven apply as well.
There is a important difference between importing a BOM (in the dependencyManagement section) and using a parent
The BOM imported in dependencyManagement only provides defaults for dependencies, but a Parent-way include the other sections too (plugins, plugin-managent, dependencies, dependencyManagement...)
So when you remove the parent spring-boot-starter-parent then you have to copy the the plugin-managent stuff you need first.

Maven Plugin for Version Management

I am looking for a possibility to manage my maven project versions.
I have some maven modules in my maven project and some of these modules are depending on others of these modules.
I want to define the version to work with globally for every module or dependency.
Is this somehow possible?
Something like
globalVersion=2.0
<groupId>test</groupId>
<artifactId>test</artifactId>
<version>${globalVersion}</version>
But as i said, not in each single pom. I mean globally for all my poms in my maven modules.
(I assume you have a parent pom common for all your modules.)
define a property in the parent pom:
<properties>
<globaleVersion>1.0.0</globalVersion>
</properties>
And define a <dependencyManagement> section in the parent pom too:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>test</groupId>
<artifactId>test</artifactId>
<version>${globalVersion}</version>
</dependency>
<dependency>
<groupId>A</groupId>
<artifactId>A</artifactId>
<version>${globalVersion}</version>
</dependency>
</dependencies>
</dependencyManagement>
And in you modules define dependencies without specifying the version (maven will find it from the dependencyManagement section of the parent)
<dependencies>
<dependency>
<groupId>test</groupId>
<artifactId>test</artifactId>
</dependency>
<dependency>
<groupId>A</groupId>
<artifactId>A</artifactId>
</dependency>
</dependencies>

Resources