I can't use a property for my project's parent version despite described as such in Spring Cloud doc - maven

In Spring Cloud Config documentation, pom.xml's parent configuration is presented with a version variable spring-boot-docs-version as such 1:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>{spring-boot-docs-version}</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>{spring-cloud-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
So I added the following in my pom.xml's properties:
<properties>
<spring-boot-docs-version>2.1.8.RELEASE</spring-boot-docs-version>
<spring-cloud-version>Greenwich.SR3</spring-cloud-version>
</properties>
But it doesn't seem to work; even by prefixing the {spring-boot-docs-version} expression with $ doesn't make maven resolve the parent POM.
Note however that I had to add this extra $ in the <dependencyManagement>:
<version>${spring-cloud-version}</version>
I searched the Spring Boot documentation too, but only found out it's not using a variable 2:
<!-- Inherit defaults from Spring Boot -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.8.RELEASE</version>
</parent>
How to use such a variable in these (external) parents' <version>tag?
Note: I also read that if you don't inherit from one of these starters, you'll loose some maven pre-configuration (like plugins & so.)

Related

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.

How to verify a Spring feature/Bug fix is available in the Spring boot version which i am using?

I am working on a spring batch program to process data from sql and write to an xml. I used staxEventItemWriter to do that. But due to this issue https://jira.spring.io/browse/BATCH-1377 i am not able to fix the namespace issue. When we look at comments on this Jira card it says its fixed in 2010. But its not available in the latest spring boot versions which i am using. i tried with the patch class described in the Jira card its working fine for me.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.demo.sitemap</groupId>
<artifactId>SqlToXml</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>SqlToXml</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</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>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>6.1.0.jre8</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-oxm -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>3.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.10</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
How to verify a Spring feature/Bug fix is available in the Spring boot version which i am using?
You are using Spring Boot 2.0.4.RELEASE. This will bring Spring Batch version 4.0.1.RELEASE. You can find more details about dependencies using the Spring Boot Initializr REST API.
The issue BATCH-1377 is marked as resolved in version 2.1.0.RC1 and is also available in 4.0.1.RELEASE.
But its not available in the latest spring boot versions which i am using. i tried with the patch class described in the Jira card its working fine for me.
The patch suggested by the contributor uses an additional property rootTagNamePrefix but this was modified as per this comment to use the naming convention {uri}prefix:root in order to be consistent with Spring WS. The issue was fixed here: https://github.com/spring-projects/spring-batch/commit/f56ee747296961917caa38fa9e14785dafc0b18b
So in your case, you need to use this naming convention if you want to add a namespace to the root tag. See example here: https://github.com/spring-projects/spring-batch/blob/f56ee747296961917caa38fa9e14785dafc0b18b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/xml/StaxEventItemWriterTests.java#L287

spring cloud and spring boot compatibility issue in pom.xml

I'm getting this error when I'm trying to run my application
java.lang.NoSuchMethodError:
org.springframework.boot.builder.SpringApplicationBuilder.([Ljava/lang/Object;)V
Please find below pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>test</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</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>
<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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>1.4.2.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
I hope this issue was related to spring cloud and spring boot version compatibility issue. Can someone please help me to resolve it?
Where possible, just use the latest versions to fix version issues.
Changing 1.4.2.RELEASE to 2.0.1.RELEASE works.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.0.1.RELEASE</version>
</dependency>
Ideally you should remove the version completely, let Spring Boot take care of it.
I tend to use dependency versions provided by Spring Cloud project in my dependencyManagement section: http://projects.spring.io/spring-cloud/
This way I don't have to manually put dependency versions and avoid problems like you just presented. Selecting dependency versions manually quickly becomes a huge pain and this approach uses versions that are tested by the community.
In case of Spring Cloud, Finchley release train works with Spring Boot 2.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>

How to create spring boot cloud maven based application where parent project is not org.springframework.cloud

I want to create spring cloud project where parent project is my common project and all other modules depends on this custom parent project and not on "org.springframework.cloud" as parent project .
I do not want to add this in my parent pom
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-parent</artifactId>
<version>Brixton.BUILD-SNAPSHOT</version>
<relativePath/>
<!-- lookup parent from repository -->
</parent>
In simple words I do not want to add spring cloud as parent in maven module hierarchy.
If you generate project using spring initializer Spring Initializer then you get
<?xml version="1.0" encoding="UTF-8"?>
http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</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>
<dependencies>
<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>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
Remove the parent section and bring in Spring Boot dependencies management as a bom.
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.5.4.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
You have to add <dependencyManagement> section in pom.xml file. Looks like,
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>

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.

Resources