How to build a Maven archetype for a Jakarta EE project

Welcome to our comprehensive tutorial on building a Maven archetype for a Jakarta EE project! In this step-by-step guide, we will empower you with the knowledge and skills to create a powerful foundation for your enterprise applications. With our expert guidance, you’ll master the process of designing a customizable archetype that adheres to best practices and accelerates your development workflow. Let’s dive into this essential tutorial and take your Jakarta EE projects to new heights!

Anatomy of a Maven archetype

Basically a Maven archetype is made up of the following elements:

  • An archetype descriptor (archetype-metadata.xml in directory: src/main/resources/META-INF/maven/). It lists all properties and the directories which contain the archetype files.
  • The prototype files which are copied by the archetype plugin (directory: src/main/resources/archetype-resources/).
  • The prototype pom (pom.xml in: src/main/resources/archetype-resources).
  • The pom for the archetype (pom.xml in the archetype’s root directory).

The good news is that you don’t need to create this structure by yourself. You can create it from an archetype follow as follows:

mvn -B archetype:generate -DarchetypeArtifactId=maven-archetype-archetype \
  -DarchetypeGroupId=maven-archetype \ -DgroupId=com.mastertheboss -DartifactId=wildfly-archetype

Here is the Maven project, which includes the skeleton we will use to define our archetype:

wildfly-project/
├── pom.xml
└── src
    ├── main
    │   └── resources
    │       ├── archetype-resources
    │       │   ├── pom.xml
    │       │   └── src
    │       │       ├── main
    │       │       │   └── java
    │       │       │       └── App.java
    │       │       └── test
    │       │           └── java
    │       │               └── AppTest.java
    │       └── META-INF
    │           └── maven
    │               └── archetype-metadata.xml
    └── test
        └── resources
            └── projects
                └── it-basic
                    ├── archetype.properties
                    └── goal.txt

Let’s customize the basic archetype

First off, let’s remove the App.java and AppTest.java which will not be part of our project. Then, let’s define the pom.xml for the archetype (top’s 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.mastertheboss.archetypes</groupId>
    <artifactId>jakarta-ee10-archetype</artifactId>
    <version>1.0.0</version>
      <name>jakarta-ee10-archetype</name>
    <packaging>maven-archetype</packaging>
    <description>Archetype used to generate a sample Jakarta EE 10 application</description>
    <properties>
        <archetype-packaging.version>3.0.1</archetype-packaging.version>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>

    </properties>

    <build>
        <extensions>
            <extension>
                <groupId>org.apache.maven.archetype</groupId>
                <artifactId>archetype-packaging</artifactId>
                <version>3.2.0</version>
            </extension>
        </extensions>
    <finalName>${project.artifactId}</finalName>

    </build>
</project>

Next, let’s add the prototype pom which contains the actual WildFly tools and Jakarta EE dependencies:

<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>${groupId}</groupId>
    <artifactId>${artifactId}</artifactId>
    <version>${version}</version>
    <packaging>war</packaging>


    <properties>
        <jakartaee.version>10.0.0</jakartaee.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <failOnMissingWebXml>false</failOnMissingWebXml>
        <version.server.bom>${version-wildfly}</version.server.bom>
        <endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.wildfly.bom</groupId>
                <artifactId>wildfly-ee-with-tools</artifactId>
                <version>${version.server.bom}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>org.wildfly.bom</groupId>
                <artifactId>wildfly-microprofile</artifactId>
                <version>${version.server.bom}</version>
                <scope>import</scope>
                <type>pom</type>
            </dependency>

        </dependencies>
    </dependencyManagement>
    <dependencies>

        <dependency>
            <groupId>jakarta.platform</groupId>
            <artifactId>jakarta.jakartaee-api</artifactId>
            <version>${jakartaee.version}</version>
            <scope>provided</scope>
        </dependency>

    </dependencies>
    <build>
        <finalName>${artifactId}</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.3.1</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.0</version>
                <configuration>
                    <source>11</source>
                    <target>11</target>
                    <compilerArguments>
                        <endorseddirs>${endorsed.dir}</endorseddirs>
                    </compilerArguments>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.wildfly.plugins</groupId>
                <artifactId>wildfly-maven-plugin</artifactId>
                <version>2.0.0.Final</version>
            </plugin>
        </plugins>
    </build>
</project>

Next, within the archetype-metadata.xml, define the fileset which includes the project source code. In our example, the archetype will pick up files from the src/main/java directory:

<archetype-descriptor
        xsi:schemaLocation="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0 http://maven.apache.org/xsd/archetype-descriptor-1.0.0.xsd
        http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0"
        xmlns="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        name="wildfly">

    <requiredProperties>
        <requiredProperty key="version-wildfly">
            <defaultValue>28.0.0.Final</defaultValue>
        </requiredProperty>
    </requiredProperties>

    <fileSets>
        <fileSet filtered="true" packaged="true">
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.java</include>
            </includes>
        </fileSet>

    </fileSets>

</archetype-descriptor>

Here are a few important tags and their purpose:

  • Required Property can be used to define properties that can be injected in the prototype pom. In our case “wildfly-version” will be prompted if running in interactive mode.
  • FileSet defines how to use the project files located in the jar file to generate a project. If a file or a directory name contains __property__ pattern, it is replaced with corresponding property value
  • packaged = “true” means that the selected files will be generated in a directory structure that is prepended by the package property

Finally, let’s add the Java class files, which are added in src/main/resources/archetype-resources/src/main/java. Here is AppConfig.java:

package ${package};

import jakarta.ws.rs.ApplicationPath;
import jakarta.ws.rs.core.Application;

@ApplicationPath("/rest")
public class AppConfig extends Application {
}

And here is the HelloREST.java file:

package ${package};

import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.UriBuilder;

@Path("/hello")
public class HelloREST {

    @GET
    public Response hello(){

        return Response
                .ok( "Hello World")
                .build();
    }

}

This is the final structure of your Archetype project:

src
└── main
    └── resources
        ├── archetype-resources
        │   ├── pom.xml
        │   └── src
        │       └── main
        │           └── java
        │               ├── AppConfig.java
        │               └── HelloREST.java
        ├── logback.xml
        └── META-INF
            └── maven
                └── archetype-metadata.xml

You need to install the archetype on your local repository with:

$ mvn clean install

Using the archetype to create a WildFly project

We will now create a sample project using our archetype. First of all, let’s move into another directory, to avoid conflicts with the pom.xml file used by our archetype:

$ mkdir demo
$ cd demo

Next, in order to use our archetype, we will refer to the com.mastertheboss.archetypes which is in our local repository:

mvn archetype:generate -DarchetypeGroupId=com.mastertheboss.archetypes  -DarchetypeArtifactId=jakarta-ee10-archetype -DarchetypeVersion=1.0.0 -DgroupId=com.example -DartifactId=demo-rest -Dversion=1.0.0

The, at the prompt, confirm or modify the archetype default properties:

[INFO] Using property: version-wildfly = 28.0.0.Final
[INFO] Using property: groupId = com.example
[INFO] Using property: artifactId = demo-rest
[INFO] Using property: version = 1.0.0
[INFO] Using property: package = com.example
Confirm properties configuration:
version-wildfly: 28.0.0.Final
groupId: com.example
artifactId: demo-rest
version: 1.0.0
package: com.example
Y: : Y

Finally, here is the project demo-rest which includes the JAX-RS Activator and a sample Endpoint:

maven archetype jakarta ee 10

Build and install it with:

$ mvn clean install wildfly:deploy

Test it with:

curl http://localhost:8080/demo-rest/rest/hello
Hello World

Conclusion

This article was a quick walk through Maven archetypes creation. We have learnt how to create a Java Enterprise project using WildFly dependencies from a custom Maven archetype.

You can find the source code for it here: https://github.com/fmarchioni/mastertheboss/tree/master/maven-archetype/jakarta-ee10

Found the article helpful? if so please follow us on Socials