Using Maven Archetype to Create New Applications Based on a Reference Architecture

Bruno Alves
The Startup
Published in
5 min readJan 10, 2021

--

Recently, I was involved in a project composed by several Java applications. All of these applications followed a layered architecture pattern specified in an architecture reference, previously discussed and documented by software architects.

However, each time I had to create a new project based on that architecture reference I had a lot of difficulties because these Java applications still use the old web.xml and a long and complex Spring application context xml file with a lot of common beans and properties that had to be changed for each new application.

Therefore, in order to have a standard between all of these applications and to facilitate the start of a new project I decided to build an archetype.

What is an archetype? An archetype is defined as an original pattern or model from which all other things of the same kind are made[1].

Using a Maven Archetype project I found a great way to enforce same code base, quality attributes, packages organization to all projects.

So let’s start! 🚀

Application architecture

For this article, I chose an application layered architecture but of course other patterns can be considered.

Thus, in the next diagram I provide the component view of our architecture reference and on which I will base the Maven Archetype project.

Building the Archetype

Step 1: First of all we must create a simple Maven project with a pom.xml file on which packaging is maven-archetype.

<groupId>pt.demo.sample</groupId>
<artifactId>demo-archetype</artifactId>
<packaging>maven-archetype</packaging>
<version>0.0.1-SNAPSHOT</version>

Under the build section we also must import the archetype-packaging extension:

<build>
<extensions>
<extension>
<groupId>org.apache.maven.archetype</groupId>
<artifactId>archetype-packaging</artifactId>
<version>3.2.0</version>
</extension>
</extensions>
</build>

Step 2: Now we must place under src/main/resources/META-INF/maven directory a XML file named archetype-metadata.xml. This file is the Archetype descriptor and describe archetypes’s metadata that must be taken into account when generating the project.

Within archetype descriptor, we can define required properties that can be passed by argument. For example, in the next block, we define the name and version of the service.

<requiredProperties>
<requiredProperty key="service">
<defaultValue>sample</defaultValue>
</requiredProperty>
<requiredProperty key="version">
<defaultValue>0.0.1-SNAPSHOT</defaultValue>
</requiredProperty>
</requiredProperties>

As we are using a multi-module project we have to define which modules we want to be considered. Following the component diagram presented above, we should have the following four modules.

<modules>
<module id="sample-${service}-starter"
dir="sample-__service__-starter"
name="sample-${service}-starter">
<!-- ... -->
</module>
<module id="${service}-rest-api"
dir="sample-__service__-rest-api"
name="sample-${service}-rest-api">
<!-- ... -->
</module>
<module id="sample-${service}-domain"
dir="sample-__service__-domain"
name="sample-${service}-domain">
<!-- ... -->
</module>
<module id="sample-${service}-data"
dir="sample-__service__-data"
name="sample-${service}-data">
<!-- ... -->
</module>
</modules>

Note that we are already making use of the required properties defined here as a placeholder.

Step 3: We will have to return to the archetype descriptor file later but for now we can already place within src/main/resources/archetype-resource directory the template folders and files we want to be considered.

Note that if we inspect pom.xml file we can verify that we can use the placeholders previously defined in archetype descriptor.

Therefore, using the placeholders it’s easy to configure the dependencies between the modules that will be generated but also the common dependencies and properties to the entire project.

So, as you can see now it’s very easy to enforce a package organization, just create the directory structure and put the pretended classes or a .empty file (if the folder is going to be empty).

Step 4: After creating all directory structure now we have to return to the archetype descriptor file. If you payed attention before I put a comment with “…” between each module tag.

Thus, we have to indicate for each module and from a base directory the files we want to include, make the filtered property true if you want to filter files by extension or name as in the example.

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

Note that we make packaged property true or false as we want the filtered files to be placed inside a package or not. In the first set of files, this make sense for java classes but in the second, we just want to put the files inside resources folder.

Final step: Now we just have to compile the whole project and after that run on the terminal the following command.

mvn archetype:generate                              \
-DarchetypeGroupId=pt.sample.archetype \
-DarchetypeArtifactId=sample-archetype \
-DarchetypeVersion=0.0.1-SNAPSHOT \
-DgroupId=pt.sample.<SERVICE_NAME> \
-DartifactId=sample-<SERVICE_NAME> \
-Dservice=<SERVICE_NAME> \
-Dversion=0.0.1-SNAPSHOT

Don’t forget to change the <SERVICE_NAME> placeholder in the command above for the name of the desired service.

After that, if you open the generated project you will have something like this:

Conclusion

I hope this article will help other developers start new projects more quickly, skipping much of the initial setup and maintaining a standard across the applications.

The project presented can be found on Github.

References

--

--

Bruno Alves
The Startup

Software engineer at Fanduel with a passion for crafting robust software architectures.