DEV Community

Cover image for Using maven build profiles to generate different artifacts
Ankit Yadav
Ankit Yadav

Posted on

Using maven build profiles to generate different artifacts

Want to use the same maven Pom file to create two or more different types of artifacts (jar/war etc.) based on some condition?

You can do it by Modifying pom files manually based on your requirement every time you build but this becomes tedious if you have to do it continuously.
Also, it will be a puzzle for developers who start working on the project when you are no longer there to guide.

We could use maven build profiles instead.

A Build profile is a set of configuration values, which can be used to set or override default values of Maven build. Using a build profile, you can customize build for different environments such as Production v/s Development environments.

Among other uses of build profiles, you can use this approach to:

  • Create builds using different parameters values
  • Create builds with different artifact types

Below I am going to show you a way with which you can use the maven profiles for the purpose of creating

  • A Jar library file to be used as a dependency by another project. OR
  • A War file to be deployed to the server directly.

Changes Required to the POM file for creating profiles:

  1. There will be some fields that will require values as parameters instead of hardcoded values:
    • artifactId - artifact id of the artifact created as end result
    • packaging - to define the type of packaging like war or jar
    • name - name of the artifact to be created
    • description - description of the artifact
  2. Now these values defined as parameters above will be passed actual values based on the build profile.
  3. The first profile is for generating war package for the springboot project having id "generate-war" We have set activateByDefault as true for this, we want the default behaviour to be creation of war file.
  4. The second is for generating library package to be used a library in other projects.
  5. You can add the dependencies based on your requirements.
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.16</version>
        <relativePath/> 
    </parent>
    <groupId>com.abc.test</groupId>
    <artifactId>${packaging.artifactId}</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>${packaging.type}</packaging>
    <name>${packaging.name}</name>
    <description>${packaging.description}</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--Other dependencies-->
    </dependencies>

    <profiles>
        <profile>
            <id>generate-war</id>
            <properties>
                <packaging.artifactId>test-api</packaging.artifactId>
                <packaging.type>war</packaging.type>
                <packaging.name>test-api</packaging.name>
                <packaging.description>TEST API project</packaging.description>
            </properties>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-maven-plugin</artifactId>
                    </plugin>
                    <!--You can any other plugins required for specific profile here-->
                </plugins>
            </build>
        </profile>
        <profile>
            <id>generate-library</id>
            <properties>
                <packaging.artifactId>test-api-lib</packaging.artifactId>
                <packaging.type>jar</packaging.type>
                <packaging.name>test-api-lib</packaging.name>
                <packaging.description>TEST API library</packaging.description>
            </properties>
            <build>
                <finalName>test-api-lib</finalName>
            </build>
        </profile>
    </profiles>

    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin>
               <groupId>org.apache.maven.plugins</groupId>
               <artifactId>maven-install-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

Enter fullscreen mode Exit fullscreen mode

To build using these profiles we use the -P parameter with the profile id as below:

mvn install -P generate-library
Enter fullscreen mode Exit fullscreen mode
mvn install -P generate-war
Enter fullscreen mode Exit fullscreen mode

Also if you are using intellij Idea then you can use the plugin as well to select the profile.

Maven Build with Profiles in Intellij IDEA

Hope this helps you if you ever face such a scenario!

Top comments (1)

Collapse
 
khmarbaise profile image
Karl Heinz Marbaise

Based on the usage of the spring boot parent is not necessary to define the maven-compiler-plugin separately with an older version than the on spring boot parent offers. Also explicitly adding maven-install-plugin is not neccessary as well..

Furthermore the definition of the java version is done via java.version property as documented in Spring Boot..Apart from using a SB version (2.7.X) which is end of open source support (spring.io/projects/spring-boot/#su...) also the last 2.7.X release has been done on November spring.io/blog/2023/11/23/spring-b...

Also it's very bad practice to try to generate two different artifacts with the same pom file.. like that.

Furthermore this produces a warning verytime you call only a simple mvn clean. (based on a good reason). Also violates the convention-over-configuration paradigm.

There are better solution to make the usage as a lib or as a spring boot application possible.

The first one is to simply use the classifier of the spring-boot-maven-plugin to produce the cli/war (jar) and a separated jar which only includes your own classes from src/main/ including resources. which can be consumed as a library with the disadvantage that it contains the main applciation class which is annotated with @SpringBootApplication and maybe other annotations as well (also the application.properties/application.yml files) which can lead to issues on the projects where you add it as a dependency..

Also based on your setup which profiles should be actived while creating a release? And the activation of the profile is not documented in your Git repo.. because if you don't define the profile you get a different result...

There is in general only a single clean solution. It means to make a multi module build which comprises at least of two modules, the main application (which contains the SpringBootApplication including configuration files etc.) and a second module which contains the part you would like to reuse (as a library).

That leads to clean separation of concern and prevents all the issues I described above.