First of all, I have to state that I’m quite fond of maven. I simply cannot imagine doing any Java enterprise software development without it and its ecosystem (Jenkins, Nexus, Sonar, etcetera.). Maven really is an invaluable tool. However, every once in a while I find that some of the basic plug-ins can prove to be a real source of headaches. E.g., I can’t recall the number of times that I cursed the release plug-in. But today the culprit turned out to be the archetype plug-in.
At the office we tend to create a lot of projects that are very similar and complex in layout and contain a lot of plumbing files, mostly spring configuration and some property files. Getting started with one of these projects can take up to a days worth of work. Therefore, I’ve wanted to create a maven archetype. So next time around, we can be up and running in a matter of minutes instead of hours.
So to get started creating my archetype I issued the command mvn archetype:create-from-project
from an already existing project. This resulted in the basic set up for my archetype inside the target/generated-sources
archetype folder. So after copying the archetype directory to a new location so it could serve as the basis for my new archetype, it now was time to fiddle with the details to get the archetype exactly as I wanted it to be. For the most part it was relatively smooth sailing. I did, however, run into some rather mind-boggling issues.
Required properties
In the maven archetype descriptor – archetype-metadata.xml
– it is possible to define default values for the main properties groupId
, artifactId
, version
, and package
. It is also possible to define additional properties that will be used for the file generation. Since we wanted a default package and version number for our newly created projects, I decided to take advantage of using default values for my properties. So I went ahead and specified a defaultValue
for the groupId
and package
, like such:
1 2 3 4 5 |
<requiredProperties> <requiredProperty key="groupId"> <defaultValue>my.company.examples</defaultValue> </requiredProperty> </requiredProperties> |
What I did find out was that if a default value is provided the user is never asked to enter the value. Leaving out the defaultValue
from the piece of XML will result in the user always being asked to enter a value. But what I was looking for was a way of asking the user to enter a value or press the enter key to accept the suggested default value. In other words, I wanted the user to be able to override the default value. But alas, the archetype plug-in doesn’t provide for this scenario.
Empty folder
When using a template for a new project one would imagine the folder structure for the new project to be laid out – even if the folders are empty. So I imagined that defining a fileSet
in the archetype descriptor pointing to my src/main/java
folder for example, would suffice:
1 2 3 |
<fileSet filtered="true" packaged="true" encoding="UTF-8"> <directory>src/main/java</directory> </fileSet> |
Unfortunately, the archetype plug-in only generates folders if they contain at least one file. For instance, suppose I’ve got a file called Example.java
inside the folder src/main/java/com/mycompany/example
and an empty folder src/main/com/mycompany/utils
. After creating a new project using mvn archetype:generate
the former will be present but the latter will not. The only way to make sure that an empty folder will wind up in the project is by explicitly adding an extra fileSet
in the descriptor file for each and every (sub)folder:
1 2 3 4 5 6 |
<fileSet filtered="true" packaged="true" encoding="UTF-8"> <directory>src/main/java</directory> </fileSet> <fileSet encoding="UTF-8"> <directory>src/main/java/com/mycompany/utils</directory> </fileSet> |
Archetype catalogue
So after having overcome the first two astonishments, my archetype was finally finished. And after thorough testing on my developer machine using mvn:update-local-catalog
, I released it into our corporate Nexus repository.
But to my complete disbelief my co-workers were unable to use the archetype. How could this be? The archetype-catalog.xml
in Nexus was correctly updated. Also, all our Maven’s settings.xml
files were pointing to our Nexus instance.
Well, after some further investigation I found that the archetype plug-in insists on going straight to the maven central repository located at http://repo1.maven.org/maven2, completely bypassing our Nexus repository.
After consulting Google some more, I found two possible workarounds:
- From the command line add an additional argument specifying the catalogue location, e.g.:
mvn archetype:generate -DarchetypeCatalog=http://
path/to/nexus/content/groups/ public/archetype-catalog.xml - Add the
archetypeCatalog
property in your maven’ssettings.xml
:
1 2 3 4 5 6 7 |
... <profile> <id>nexus</id> <properties> <archetypeCatalog>http://path/to/nexus/content/groups/public/archetype-catalog.xml</archetypeCatalog> </properties> ... |
The answer is a bit late, but anyway. It is not (or not longer) true that maven never ask for required additional properties with default value:
Instead Maven ask for properties it in two rounds:
– In the first round it ask for properties without default value.
– Then it prints a summary “Confirm properties configuration” and ask: “Y:”, if you enter “N”
– It starts a second round and ask for all properties.
That is still quite unexpected but it works
(Testest with Maven 3.6.0 and Archetype Plugin 3.0.1)