Maven module using spring-boot - java

I like to configure my applications in maven by creating modules like;
<groupId>com.app</groupId>
<artifactId>example-app</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>app-api</module>
<module>app-impl</module>
<module>app-web</module>
</modules>
The modules then use the 'example-app' as the parent.
Now I want use 'spring-boot' for my web application.
Is there a way to configure maven so that my 'app-web' is a spring-boot application?
The problem I'm facing is that you have to use spring-boot as a parent.

You don't have to use the spring-boot-starter-parent, it's just a way to get started quickly. All it provides are dependency management and plugin management. You can do both yourself, and you can use the spring-boot-dependencies (or equivalently the parent) to manage dependencies if you want a halfway step. To do that, use scope=import like this
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<type>pom</type>
<version>1.0.2.RELEASE</version>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

Another alternative, is to include in the parent pom, the parent declaration for spring boot, as shown in this post
example-app pom.xml:
<project>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.5.RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
// rest of the example-app pom declarations
</project>
After that, in the modules poms (app-web, app-impl, etc.), you declare example-app as parent, but now you can include the starter dependencies as you would normally do in a regular project.
app-web pom.xml:
<project>
<parent>
<groupId>org.demo</groupId>
<artifactId>example-app</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<name>app-web</name>
<artifactId>app-web</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>org.demo</groupId>
<artifactId>app-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.demo</groupId>
<artifactId>app-impl</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
// rest of the app-web pom declarations
</project>
Regarding version management, what i used in these examples aren't exactly the best practices, but since is out of the scope of the question i skipped dependencyManagement and parent properties usage.
Also, if there is a starter that is used in every module, you can declare the dependency in the parent pom and then all the modules will inherit it (for example spring-boot-starter-test)

Related

maven dependency management mechanism, the priority about dependency management which using import scope

There are two examples.
example 1.
pom of project A is a simple pom:
<groupId>org.demo</groupId>
<artifactId>kafka-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<name>kafka-demo</name>
pom of project B:
<parent>
<artifactId>kafka-demo</artifactId>
<groupId>org.demo</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>child-one</artifactId>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.0.3.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<scope>compile</scope>
</dependency>
</dependencies>
In this example, spring-boot version of project B is 2.0.3.RELEASE.
example 2.
pom of project A.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.3.1.RELEASE</version>
<relativePath/>
</parent>
<groupId>org.demo</groupId>
<artifactId>kafka-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<name>kafka-demo</name>
pom of project B is the same as the previous example.
<parent>
<artifactId>kafka-demo</artifactId>
<groupId>org.demo</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>child-one</artifactId>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.0.3.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<scope>compile</scope>
</dependency>
</dependencies>
In the example two, spring-boot version of project B is 2.3.1.RELEASE.
My question is in example 2, why the version of spring-boot is 2.3.1, rather than 2.0.3.
This scope is only supported on a dependency of type pom in the section. It indicates the dependency to be replaced with the effective list of dependencies in the specified POM's section. Since they are replaced, dependencies with a scope of import do not actually participate in limiting the transitivity of a dependency.
AFAIK, dependencyManagement that is directly declared in the POM is always stronger than imported dependencyManagement.
It is wrong to assume that an import is the same as declaring the list from the BOM at the same place.
So in your second example, one of the BOMs is used as parent, so it is directly used in the resulting effective POM, while the other is an import, which is less strong.

How to exclude specific dependencies from spring-boot-starter-parent

I am using a legacy Spring application and want to migrate to Spring Boot. My intention is to use the spring-boot-starter-data-jpa. For this reason I have added following section in pom.xml (which manages all spring-boot-dependencies):
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
</parent>
But this is screwing up certain dependencies which I need to retain for time being. I am currently using Selenium dependencies (version 2.53.0; added transitively from another project) but spring-boot is fetching dependencies of 3.9.1.
I want to exclude 3.9.1 dependencies but the exclusion filter is not working as expected.
Just to summarize, I want to use spring-boot-starter-parent and spring-boot-starter-data-jpa but not the managed selenium-java from spring-boot-dependencies.
Appreciate any help in this regard.
Instead of messing around with <excludes> and then try to figure out what you need to include again (after figuring out what you excluded). Just override the version as explained here in the Spring Boot Reference Guide.
Assuming you are using the spring-boot-starter-parent as the parent you can just add a <selenium.version> to your <properties> section to specify which version you want.
<properties>
<selenium.version>2.53.0</selenium.version>
</properties>
This will make Spring Boot use the version you want.
Mention your dependency in pom.xml which you need to exclude in exclusion tag. Then excluded dependency will not be downloaded:
<dependency>
<groupId>sample.ProjectA</groupId>
<artifactId>Project-A</artifactId>
<version>1.0</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<!-- declare the exclusion here -->
<groupId>sample.ProjectB</groupId>
<artifactId>Project-B</artifactId>
</exclusion>
</exclusions>
</dependency>
Remove the deppendency from the starter pom. Use the exclsuions tag in pom.xml. For example to remove the actuator dependency
<?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>demo-1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>demo-1</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.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</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</exclusion>
</exclusions>
</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>
</project>

How to avoid telling the version in dependency with maven?

I have a project that has 2 modules, the first two work without version, but when I added a new one is asking me for the version.
Why is letting me use the first two without version and is asking for a version in the third one?
Maven project to create ear
....
<parent>
<groupId>es.imas.gestresi</groupId>
<artifactId>gestresi</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
...
<dependencies>
<dependency>
<groupId>es.imas.gestresi</groupId>
<artifactId>gestresi-web</artifactId>
<type>war</type>
</dependency>
<dependency>
<groupId>es.imas.gestresi</groupId>
<artifactId>gestresi-ejb</artifactId>
<type>ejb</type>
</dependency>
<dependency>
<groupId>es.imas.gestresi</groupId>
<artifactId>test-dialog</artifactId>
<version>0.0.1-SNAPSHOT</version> <!--Ask for version-->
<type>war</type>
</dependency>
</dependencies>

Maintaining two different Spring boot versions in single Maven package

Let's say we have a shared-lib package. The pom for the same is as follows:
<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.project.microservice-a</groupId>
<artifactId>shared-lib</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>shared-lib</name>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<start-class>com.projects.lib1.Application</start-class>
<java.version>1.8</java.version>
</properties>
....
....
</project>
There are projects using above shared library, having following pom.xml
<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.projects.microservice</groupId>
<artifactId>accounts</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>accounts</name>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.3.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>com.project.microservice-a</groupId>
<artifactId>shared-lib</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
....
<dependencies>
Then there is one special subsystem running on Spring-boot-starter-parent.1.3.5 as parent, which won't take shared-lib with Spring-boot-starter-parent-1.2.3.
For importing shared-lib with Spring-boot.1.3.5, we need to modify pom.xml with parent as Spring 1.3.5 version and then build. This causes maintenance issues while building all subsystems, as Jenkins CI builds all JARs from Github with master branch. We can specify a separate branch manually, but maintaining same code for two branch is plain repetition.
Can anyone suggest a solution, which IMO may be a way to achieve one of these:
Create a package embedding both Spring 1.2.3 and Spring 1.3.5, and specifying required dependency version in other subsystems.
Bulid original client package with Spring Boot 1.3.5, and force it to use older version of Spring boot when used a dependency in required subsystems.
Let's say these are your dependencies for each project:
shared-lib:
spring-boot-foo:1.2.3
project-a:
shared-lib
spring-boot-bar:1.2.3
project-b:
shared-lib
spring-boot-baz:1.3.5
Now you want project-a to use 1.2.3 of all spring-boot libraries, and project-b to use 1.3.5, regardless of what spring-boot libraries shared-lib specifies?
Put the following in your pom.xml:
<properties>
<spring-boot.version>1.3.5.RELEASE</spring-boot.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<!-- Import dependency management from Spring Boot -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
If your projects have a common parent pom.xml, you can put it there and simply change spring-boot.version value to something else per-project as you see fit. Otherwise you'll have to duplicate it.
Alternatively if this so-called BOM (<scope>import</scope>) doesn't work, you can list each dependency explicitly, e.g.:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-foo</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-bar</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-baz</artifactId>
<version>${spring-boot.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
Read more about managing spring-boot dependencies: http://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-build-systems.html
UPDATE:
You can manage other dependencies the same way as necessary. For example:
<properties>
<spring-data-releasetrain.version>Gosling-SR4</spring-data-releasetrain.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-releasetrain</artifactId>
<version>${spring-data-releasetrain.version}</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>

How spring boot create jar file in target without having plugin in pom

I am reading spring-boot doc and there they said that
To create an executable jar we need to add the spring-boot-maven-plugin to our pom.xml. Insert the following lines just below the dependencies section
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
Following are my main pom which includes other module
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.5.RELEASE</version>
</parent>
<groupId>de.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<description>demo</description>
<properties>
<java.version>1.6</java.version>
<joda.version>2.5</joda.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- joda time -->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>${joda.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<modules>
<module>db</module>
<module>web</module>
</modules>
following is the db
<parent>
<groupId>de.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>db<artifactId>
<description>demo</description>
<dependencyManagement>
<dependencies>
<!-- spring data jpa -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
</dependency>
<!-- hibernate -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
</dependency>
</dependencies>
</dependencyManagement>
following is web
<parent>
<groupId>de.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>web</artifactId>
<dependencyManagement>
<dependency>
<groupId>com.example</groupId>
<artifactId>db</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencyManagement>
I have created multi-module project. I am using spring boot parent. In any of my modules pom I do not have above plugin but still it create jar file in target folder after I run following command on web module as base directory
mvn clean install spring-boot:run
I am missing any thing to understand. Please do comment.
Maven uses maven-jar-plugin to build a non executable jar file and spring-boot-maven-plugin is used to create an executable jar.
In you case even though you do not specify the spring-boot-maven-plugin, the maven-jar-plugin will create the jar file.
You can check this when you do a mvn install and see the build logs.

Categories