Multiple module Spring Boot app - maven

We have a Spring Boot app (exposing REST services) with multiple modules and for dev purposes we're using the default Spring Boot build approach - Maven builds it as one executable war file, that has Tomcat embedded into it.
For productive deployment purposes this doesn't work. We already have web app servers setup and we need a regular, non-executable war, that can be deployed on those servers. I already figured out, how I can build it.
We also will have another, related web apps (war files) deployed on the same productive servers (e.g. - simulator of the app). Of course, they will use (some of) the same modules, so the question it raises is how to setup maven to build the war and the module jars outside of it, so the other apps (war files deployed on the same server) could have dependencies on them. I couldn't find a good explanation/example how to do that.
Any ideas, links, blogs?

This is really more of a Maven question than Spring Boot. When you have a multi-module project Maven still creates individual artifacts for each module so you can still reference them as dependencies elsewhere.
For example in my setup with Spring boot I have the parent project and the modules underneath it. Most of the modules are jar artifacts, some with dependencies on other modules in the project and of course some external dependencies as well. By using the parent we can standardize some of the versions used in the dependencies using placeholders in the parent. Since the artifacts are still built and published separately you can reference them in other projects, which is what I believe you are asking.
For example (just the main tags and not all of them):
Parent:
<groupId>com.somecompany</groupId>
<artifactId>project-parent</artifactId>
<packaging>pom</packaging>
<version>1.1.2-SNAPSHOT</version>
<modules>
<module>module1</module>
<module>module2</module>
</modules>
Module1:
<parent>
<groupId>com.somecompany</groupId>
<artifactId>project-parent</artifactId>
<version>1.1.2-SNAPSHOT</version>
</parent>
<groupId>com.somecompany.tools</groupId>
<artifactId>project-tools-core</artifactId>
<version>1.1.2-SNAPSHOT</version>
<packaging>jar</packaging>
Module2:
<parent>
<groupId>com.somecompany</groupId>
<artifactId>project-parent</artifactId>
<version>1.1.2-SNAPSHOT</version>
</parent>
<groupId>com.somecompany.apps</groupId>
<artifactId>project-webapp</artifactId>
<version>1.1.2-SNAPSHOT</version>
<packaging>war</packaging>
<!-- dependency on other module -->
<dependency>
<groupId>com.somecompany.tools</groupId>
<artifactId>project-tools-core</artifactId>
<version>${project.version}</version>
</dependency>
Some Other Project:
<groupId>com.somecompany.apps</groupId>
<artifactId>project-webapp-services</artifactId>
<version>1.3.0-SNAPSHOT</version>
<packaging>war</packaging>
<!-- dependency on other module which is published -->
<dependency>
<groupId>com.somecompany.tools</groupId>
<artifactId>project-tools-core</artifactId>
<version>1.1.1</version>
</dependency>
So in this case assuming you had published version 1.1.1 of your parent and its modules you can have another project refer to any of those published artifacts. Maybe it is the release and publishing step you are missing.

Related

Why spring.io generate pom without version?

I'm new to springboot and using spring.io to create project in order to create microservices.
When creating a project using spring.io website, a pom is created with all the relevant
dependencies but versions are not added.
Should I add the versions myself looking the maven repository jar (all jars include
versions on them)?
All dependencies (and configurations) are managed by Spring Boot. The parent of the project you generated with Spring Initializr has the parent set to spring-boot-starter-parent:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
The parent of spring-boot-starter-parent is spring-boot-dependencies which defines all dependency versions.
Therefore you don't need to specify any versions of the starter dependencies or their dependencies manually.
Please take a look at The Spring Boot Starter Parent on Baeldung for a quick overview.

Ensure that a maven module is built before all others without a project parent pom

I've been asked to work on a maven project with multiple modules having the following parent:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>${spring.boot.version}</version>
</parent>
some of these modules depend on each other and such dependencies are imported in the <dependencies> section.
I created a test commons module to be used as a test-jar and imported by all other modules but in order for this to work properly it has to build before the others at least once. I researched about ways to accomplish this and it seems that the proper way is to have a parent pom for the project and have it deal with the build order. Unfortunately I am not allowed to do this.
Therefore I was wondering if there is an alternative approach to ensure that this module builds before the others.
Thank you for your attention

spring-boot-starter-parent: Can this be included as dependency

I was understanding something in spring boot and to being with, used a very simple snippet, like adding this in pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
</parent>
As I understand <parent> in this context means that in my pom.xml, there we have a parent pom.xml (saw the pom.xml file for spring-boot-starter-parent) which will have list of dependencies.
The important thing is that it is only pom packaging, and NOT a real jar / binary (please correct if I am wrong)
I saw the following in mvn repository:
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-parent -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<type>pom</type>
</dependency>
My doubt is:
How can we include it as an dependency , it is just a pom packaging (and not a real jar / war), which acts as central place which holds common dependencies? Is it allowed? I tried adding in my project, but saw errors in STS IDE.
How does this get downloaded? Can we see the contents of this "parent"
First off, you've probably missed the meaning of parent pom in this case.
Spring boot of any specific version (2.2.1 in this case) comes with a bunch of possible integrations with many technologies / libraries. So it provides "default" versions of the libraries to work with because its very hard to check that it compatible with all possible versions of all libraries. You can of course provide your own version but then you should test a compatibility as an application maintainer.
So If you'll checkout the source code of spring-boot-starter-parent pom, you'll see that it provides some plugins and plugin management and more importantly inherits from another pom called spring-boot-dependencies
Note it doesn't add any dependencies to your project. It only defines a dependencyManagement section. This means that once you'll use the dependency in your project (that inherits) from this pom, you don't have to specify a version, only group id and artifact id.
Again, that's because spring boot offers by default very specific versions of thirdparties - the version that it was verified that it's compatible with...
Now as for the second part of the question - indeed it doesn't make sense to include dependency with packaging pom like you've posted, could you please provide a link where exactly you've seen this?
Sometimes when people adopt spring boot in their projects they already have have some parent, so they can't use the inheritance, in this case they can use a very special maven scope "import" and use the dependency on pom treating it as BOM (bill of materials) - frankly a pretty advanced stuff in maven. But spring boot uses this feature for these cases.
The dependency inclusion looks like this:
<dependencies>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.2.1.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
Note, the `import line. From maven's site: This is meant to allow dependency management information such as versions and excludes be retrieved from a remote POM file.
Here is a tutorial about this topic
#CuriousMind, including the spring-boot-starter-parent as a dependency is like trying to instantiate an interface or Abstract Class in Java. As you noticed, its packaging is pom, meaning it is just a maven artifact to help configure your maven project. Jar and War will contain some java binaries. I think the MVN repository code automatically generate all sample as dependencies..

How to import all provided Wildfly libraries in my maven project?

Is there a way to translate this human language in an xml codeblock that Maven will happily understand?
Hey Maven, look you are a great dependency management system. I am working on a JavaEE project which is intended to be deployed on Wildfly 10.1.0. Please put all Libraries that are specified in Wildflys parent BOM http://repo1.maven.org/maven2/org/wildfly/wildfly-parent/10.1.0.Final/wildfly-parent-10.1.0.Final.pom on the compiletime classpath and consider them as provided by Wildfly at runtime. And please dont bother me to list every single referenced artifact in the dependencies section of the projects pom file. Thank you Maven, you are so cool.
To clarify:
As far as I understand, importing the bom file in the dependencyManagement section of my pom file will only spare me to specify the Version Number of every single artifact, but I will still have to declare every artifactID and groupID.
This is indeed discussed here How to use BOM file with Maven
But in this answer is also stated:
Then you do not have to specify the version attribute of a dependency.
I would prefer to declare only that I am using wildfly and then be able to use all client libraries without declaring any other dependencies.
But I must admit, I have the feeling to miss something obvious. There should be an easy way to do this.
If you want everything in a another pom to be set as a dependency and as provided you can specify that in your pom. A minimal pom for wildfly 10.1.0.Final that includes everything seems to be 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>wft</groupId>
<artifactId>wft</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>wft</name>
<description>wft</description>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<failOnMissingWebXml>false</failOnMissingWebXml>
</properties>
<dependencies>
<dependency>
<groupId>org.wildfly</groupId>
<artifactId>wildfly-spec-api</artifactId>
<version>10.1.0.Final</version>
<type>pom</type>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
But I would still recommend doing it the way that wildfly does it themselves, which is to put the BOM in the depencency management section and declare artifacts as you need them. Why? I don't know other than it's cleaner to read and maybe easier for maven/java to compile and build.

One Spring Boot project, deploy to both JAR or WAR

Is there a way to have a single Spring Boot project be packagable into both JAR and WAR without changing the pom.xml or the application source?
I've read Converting a Spring Boot JAR Application to a WAR, but it converts the project to WAR and it loses the ability to be packaged as JAR.
I don't expect mvn package to do both. What I want is something like mvn i-want-a-jar and it would package the project as JAR. Or I could run mvn i-want-a-war and it would package the project as WAR.
Is this possible?
I managed to do it by adding
<packaging>${packaging.type}</packaging>
to the POM file and then setting different profiles for JAR and WAR:
<profiles>
<profile>
<id>jar</id>
<properties>
<packaging.type>jar</packaging.type>
</properties>
</profile>
<profile>
<id>war</id>
<properties>
<packaging.type>war</packaging.type>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</profile>
</profiles>
Now mvn package -P war produces a WAR and mvn package -P jar produces a JAR.
Another option is to create separate modules for JAR and WAR, but I didn't go that route.
What's wrong with a WAR file that's executable? Isn't that what you really need?
P.S. like
java -jar name.war
We've recently had a similar requirement, where an existing Spring Boot based project that was originally packaged as an executable Jar needed to support Tomcat and WildFly deployments.
Due to some dependencies used in this project (for example WebJars), a simple switch to WAR package wasn't an option since some of those dependencies were required for WildFly (VFS support) but not for other deployment.
The solution was to restructure the project modules in a way that core module contained the actual project but without having Spring Boot’s plugin applied, while several package modules would depend on core module and configure deployment artifact specifics (Boot and other plugins, deployment specific dependencies etc.).
That way project build was able to generate multiple deployment artifacts (Boot's executable JAR, traditional WAR and WildFly specific WAR) in a single build run.
In case anyone finds this useful, the sample project to demonstrate the approach is available on Github. The project can be built by either Gradle or Maven.

Resources