Introduction
Let's say that after a lot of research, trial and errors, you set up a base maven project with a combination of frameworks and a bunch of tricky configurations. Your project works now, it prints
Wouldn't be easier if you could incorporate this customized project to a maven catalog so you can instantiate it from the terminal with a
Maven can take a project folder and generate the maven archetype file (a jar) that can be later installed on a maven proxy/repository to be available for all the people that have access to it. This is what this tutorial is about.
"Hello World!"
in the browser window, text file or terminal, and you feel proud of yourself for being able to set up the whole thing. Now that you have this small code base, you can make a copy of the project folder and rename it as template-xyzw-project
so if you (or any other programmer) wish to start a new project, you copy this template-xyzw-project
folder, rename it and apply the appropiated tweaks. Lot of work, right?
mvn archetype:generate
command instead of copy/paste/adjust everything?
Example Project
pom.xml
that lists all the dependencies, you can also use a project of your own if you prefer.
Generate the base-archetype
cd
into the project directory (or, in the case of a multi-module project, cd
into the parent/aggregator project) and run the following command:
$ mvn archetype:create-from-projectThis will generate a bulk of files and folders under the
target/generated-sources/archetype
directory:
.
├── src
│ ├── main
│ │ └── resources
│ │ ├── archetype-resources
│ │ │ └── src
│ │ │ └── main
│ │ │ ├── java
│ │ │ │ ├── portlets
│ │ │ │ └── services
│ │ │ │ └── impl
│ │ │ └── webapp
│ │ │ ├── VAADIN
│ │ │ │ ├── themes
│ │ │ │ │ └── test-portlet
│ │ │ │ └── widgetsets
│ │ │ └── WEB-INF
│ │ │ └── spring-conf
│ │ └── META-INF
│ │ └── maven
│ └── test
│ └── resources
│ └── projects
│ └── basic
└── target
├── classes
│ ├── archetype-resources
│ │ └── src
│ │ └── main
│ │ ├── java
│ │ │ ├── portlets
│ │ │ └── services
│ │ │ └── impl
│ │ └── webapp
│ │ ├── VAADIN
│ │ │ ├── themes
│ │ │ │ └── test-portlet
│ │ │ └── widgetsets
│ │ └── WEB-INF
│ │ └── spring-conf
│ └── META-INF
│ └── maven
└── test-classes
└── projects
└── basic
From this folder structure you can discard the target
directory sub-tree (the red one), just mvn clean
it.
com.test.portlets
to com.organization.application.portlets
and adjust all the package references (updating all the xml, properties, etc files). That's the next step.
Adjusting the archetype
cd target/resources/archetype
) or you can make a copy in another directory of the archetype
folder and cd
into it, the second option is preferred as if you screw some configuration file, you can start over making another copy from the original archetype
folder, it's up to you.
pom.xml
in the archetype directory, it describes the project as a maven archetype (yes, the archetype
folder is indeed a maven project), you can change the groupId
, artifactId
and version
properties used to address the project in the GAV way, modify these properties to change the archetype name.
archetype-metadata.xml
located under the src/main/resources/META-INF/maven
directory. This file groups the resources as file sets (fileSets
) that are going to be filtered by the archetype during the generation process, every file set is of the form:
-
filtered="true"
indicates that the resource files of the file set should be parsed. Maven will use Apache Velocity templating framework to substitute/replace/conditional replace values in your files. -
packaged="true"
From the documentation: "flags maven that the resource files have to be packaged, which means the selected files will be generated/copied in a directory structure that is prepended by the package property. They can be non-packaged, which means that the selected files will be generated/copied without that prepend." -
encoding="UTF-8"
indicates that your files are in the specified encoding.
archetype-metadata.xml
should look something like this:
You have to manually add the file sets that aren't listed in the above xml, normally you wouldn't have to do that, but this project employs some files that maven thinks shouldn't be fitlered and it groups them in a non-filtered file set. Sometimes you have to delete some of this maven generated file sets, like those that group IDE files (e.g,. .settings
, .project
, etc) that you forgot to manually delete from the project folder prior to running mvn archetype:create-from-project
.
.scss
located inside the folder VAADIN/themes/test-portlet
.
-
For README and README.md, you only have to change the lines 27-34 in the above
archetype-metadata.xml
to: Open those README files and add the following lines at the beginning of the file (if they are not already there):#set( $symbol_pound = '#' ) #set( $symbol_dollar = '$' ) #set( $symbol_escape = '\' )
Every file that you want to be filtered by maven has to start with those lines, even the.java
files, but don't worry, maven archetype plugin have done this for you with all the file-sets that are initially listed in thearchetype-metadata.xml
file, so you only add those that doesn't appear in a filtered file set (or in any file set at all). Then add the value${rootArtifactId}
whenever you want the supplied user project name to appear.#set( $symbol_pound = '#' ) #set( $symbol_dollar = '$' ) #set( $symbol_escape = '\' ) README for module ${artifactId} =============================== This module belongs to the project ${rootArtifactId}
-
For the
.scss
files, first remove the.scss
include from the unfiltered file set: Now include the.scss
files in a new file set: As done above, open the.scss
files and add the#set
lines, then replace those values that contains the project name (test-portlet
) with${rootArtifactId}
, for example, open the filestyles.scss
: Then replacetest-portlet
with${rootArtifactId}
: Remember to check the java source files, and adjust those variables, methods, commets, etc that depends on the supplied project name, substitute them with${rootArtifactId}
. Note that you can even tweak the code comments to reflect the user application name. Repeat the process with all the files you want to include and filter.com.test.portlets
with the user supplied package name using the${package}
variable. There are another variables you can use:Variable Meaning ${rootArtifactId}
Already explained above, it holds the value entered by the user as the project name (the value that maven ask as the artifactId:
in the prompt when the user runs the archetype)${artifactId}
If your project is composed by one module, this variable will have the same value as ${rootArtifactId}
, but if the project contains several modules, this variable will be replaced by the module name inside every module folder, for example: given a module namedportlet-domain
inside a project namedportlet
, all the files inside this module folder that are to be filtered will have the value of the variable${artifactId}
replaced byportlet-domain
whereas the${rootArtifactId}
variable will be replaced byportlet
${package}
The user provided package for the project, also prompted by maven when the user runs the archetype ${packageInPathFormat}
The same value as ${package}
variable but replacing'.'
with the character'/'
, e.g:, for the packagecom.foo.bar
this variable iscom/foo/bar
${groupId}
The user supplied groupId
for the project, prompted by maven when the user runs the archetype${version}
The user supplied version
for the project, prompted by maven when the user runs the archetype
__rootArtifactId__
. For example, rename the VAADIN/themes/test-portlet/test-portlet.scss
to VAADIN/themes/test-portlet/__rootArtifactId__.scss
, so it will be renamed as the user supplied project name with the extension .scss
. Again, repeat this process with all those files and/or folders that you want to rename to reflect the user's project name.
Further tweaking
com/your-company/your-application-name
?
Wouldn't be even nicer if some of the web.xml
values reference your application name instead of the test-portlet
inherated from the template?
package
in the file set, it will copy the src folder content and paste it under a folder that represents the user provided project package name.
Creating the archetype (again)
cd
in the parent archetype and run:
$ mvn installThis will re-generate the
target
folder and the test-vaadin7-portlet-archetype-1.0.0-SNAPSHOT
jar file, if you want to change the archetype project (thus, change the name of the jar name), remember to edit the archetype pom.xml
file groupId
and artifactId
properties.
Test your archetype locally
mvn install
line executed in the previous section will generate a file archetype-catalog.xml
in your ~/.m2
directory with the following content:
Then, type:
$ mvn archetype:generateYour newly deployed archetype will be listed as the last one of a list that will appear in your terminal, choose the archetype, fill in the parameters and hit enter, open up your file browser and check that all the generated files accomodates to the supplied parameters.
Uploading your archetype to your local maven proxy
maven-archetype
for Packaging. Upload the archetype jar generated in the target
folder and click the button "Upload Artifact(s)", after this, the archetype should be available for all the user that have access the the proxy.
Multi-module projects
application-persist
subproject, the web application that serves as the application front-end can be in a application-webapp
subproject, and so on. All these submodules would be controlled by an Aggregator Project.
The project layout should be in hierarchical form, the parent/aggregator project must contain the module subprojects directories inside it. If you start from a flat layout structure and run mvn archetype:create-from-project
, maven will generate the module archetype rosource folders in the directory /src/main/resources
, then in the archetype creation (mvn install
) it will complain that it can't find the archetype resource files inside the folder /src/main/resources/archetype-resources
and will exit the execution with an error message. To solve this problem you have to manually move the module archetype resources to the /src/main/resources/archetype-resources
directory or rearrange your project structure to the hierarchical form.
Is usually the case that the project modules are named <project-name>-module-name
and reside inside the parent folder named <project-name>
. For example, given a project named nextgeo
with the modules persist
, web-services
and web-app
, a common project folder names for this modules would be: nextgeo-persist
, nextgeo-web-services
and nextgeo-web-app
all inside the nextgeo
folder. To process a project layout such as this, run mvn archetype:create-from-project
inside the project parent folder, then rename the subfolders nextgeo-persist
, nextgeo-web-services
and nextgeo-web-app
(inside the src/main/resources/archetype-resources
folder) to: __rootArtifactId__-persist
, __rootArtifactId__-web-services
and __rootArtifactId__-web-app
, also in the archetype-metadata.xml
you would see that the file-sets are grouped together by a <modules>
tag:
Change the base project name (nextgeo
) with the variable ${rootArtifactId}
, except for the dir
attribute that points to a folder name (this must remain equal to the phisycal folder name or maven won't be able to copy/filter the folder and its content), like this:
Everything else in the process stays the same, after you finish editing your files, run mvn install
and it should work as well as before, now your user can make an instance of the archetype by running mvn archetype:generate
. It the user provides, for example, the project name wumpus
(rootArtifactId = wumpus
), the generated folders should be: wumpus-persist
, wumpus-web-services
and wumpus-web-app
, all inside the wumpus
parent folder.
Summarized process
cd
in the project folder.- Run
mvn archetype:create-from-project
. cd
in the<project-folder>/target/generated-sources/archetype
.- Make a copy of the archetype folder (Optional).
- Delete the
target
subfolder (Optional). - Change the archetype
groupId
,artifactId
,version
anddescription
for your archetype in thepom.xml
. - Edit the file
<archetype-folder>/src/main/resources/META-INF/maven/archetype-metadata.xml
, add the file-sets you consider neccesary, edit the existing ones, remember that the attributefiltered="true"
will filter the files in the file-set replacing variables like${rootArtifactId}
with the project name given by the user in the form of theartifactId
that maven ask him/her during generation (that moment when the users uses your archetype). Also remember thatpackaged="true"
will copy the files in the file-set in a destination folder that matches the package given by the user during generation. - Edit the files you want to be specially processed, remember whenever you see the project name (your project name) replace it with the
${rootArtifactId}
variable. - Rename those files/folders that you want reflect the user provided project name during generation with
__rootArtifactId__
. - If your project is a multi-module project, then rename the modules folders using
__rootArtifactId__
inside the name (only if the module folder name contains a reference to the project name), and update thearchetype-metadata.xml
module
tags accordingly. Remember that${rootArtifactId}
will contain the project name whereas${artifactId}
will contain the module name. - Run
mvn install
from the archetype folder. - Test it using
mvn archetype:generate
, search for the last entry in the list.
After step 11, you should run mvn archetype:update-local-catalog in folder where your archetype resides. Archetype plugin reads archetype catalogs. Google about it.
ReplyDeleteThanks for the suggestion and sorry for the late reply.
DeleteVery useful article!!!
ReplyDeleteThank you very much!!!
You're welcome, glad it was of help! And sorry for taking so long to answer the comment.
DeleteThank you for this simple and straightforward overview of the archetype creation process.
ReplyDeleteYou're welcome :)
DeleteSorry for the late reply.
+1 Thank you for this tutorial.
ReplyDeleteYou're welcome, glad it helped, sorry for the late reply.
DeleteI have a xml file it's path is src/main/resources/archetype-resources/src/main/resources/sql/myapp/DemoUser.xml.when execute mvn archetype:generate I specify artifactId is foo.bar and package is com.foo.bar(-DartifactId=foo.bar -Dpackage=com.foo.bar) but I want to DemoUser.xml in folder sql/bar/DemoUser.xml, how to implement this? That is replace myapp to bar.
ReplyDeleteWhat about renaming your folder to `src/main/resources/archetype-resources/src/main/resources/sql/__artifactId__/DemoUser.xml` and then specify the artifactId as bar and the groupId as com.foo?
DeleteHope it helps.
Thanks! I resolved it by this way: in `archetype-resources/pom.xml` I resolved app name from artifactId. #set ($artifactId = "${artifactId}")
Delete#set ($index = $artifactId.indexOf('.'))
#set ($index = $index + 1)
#set ($appName = $artifactId.substring($index)). Then in archetype-metadata.xml I add appName property and default value:
${appName}
. It seems you must put velocity syntax in pom.xml, if you put in archetype-metadata.xml it cannot be resolved.
Thanks!
ReplyDeleteSorry for the late reply.
hi I have a question of how to specify a default package value so user do not need specify a package parameter explicitly? please see http://stackoverflow.com/questions/38419903/when-execute-maven-archetype-generate-how-to-specify-a-default-package-value-cor
ReplyDeleteHello , I have a question, what if you want a json file to be filtered? because if you add the lines
ReplyDelete#set( $symbol_pound = '#' )
#set( $symbol_dollar = '$' )
#set( $symbol_escape = '\' )
then it will become an invalid json file. Thank you!
why when put the command mvn archetype:generate and then put the number of an archetype give this error:
ReplyDelete[ERROR] ResourceManager : unable to find resource 'archetype-resources/pom.xml' in any resource loader. ????
Hi
ReplyDeleteAm trying to create the new archetype as per your tutorial , but i do not want the .java files to include , in my instance of the module structure created based on the new archetype , can you please help me how to do this
This comment has been removed by the author.
ReplyDeleteHello, I got a question:
ReplyDeleteHow can I control that generate or not a file by a required property?
e.g:
if (prop.use.redis == true) {
generateFile("src/main/resources/redis.xml");
}
else {
System.out.println("do not need generate redis.xml");
}
This comment has been removed by the author.
ReplyDeleteThis is my first time visit to your blog and I am very interested in the articles that you serve. Provide enough knowledge for me. Thank you for sharing useful and don't forget, keep sharing useful info: Visit Office Rental Singapore
ReplyDeleteThis comment has been removed by the author.
ReplyDeleteFrom your discussion I have understood that which will be better for me and which is easy to use. Really, I have liked your brilliant discussion. I will comThis is great helping material for every one visitor. You have done a great responsible person. i want to say thanks owner of this blog.
ReplyDeletePython Online certification training
python Training institute in Chennai
Python training institute in Bangalore
Very interesting to read thanks
ReplyDeleteBest salesforce training in chennai
Very Clear Explanation. Thank you to share this
ReplyDeleteCCNA Course in Chennai
CCNA Training in chennai
I am obliged to you for sharing this piece of information here and updating us with your resourceful guidance. Hope this might benefit many learners. Keep sharing this gainful articles and continue updating for us.
ReplyDeleteoneplus mobile service centre in chennai
oneplus mobile service centre
oneplus service center near me
Your very own commitment to getting the message throughout came to be rather powerful and have consistently enabled employees just like me to arrive at their desired goals.
ReplyDeleteAnd indeed, I’m just always astounded concerning the remarkable things served by you. Some four facts on this page are undeniably the most effective I’ve had.
MATLAB TRAINING IN CHENNAI | Best MATLAB TRAINING Institute IN CHENNAI
EMBEDDED SYSTEMS TRAINING IN CHENNAI |Best EMBEDDED TRAINING Institute IN CHENNAI
MCSA / MCSE TRAINING IN CHENNAI |Best MCSE TRAINING Institute IN CHENNAI
CCNA TRAINING IN CHENNAI | Best CCNA TRAINING Institute IN CHENNAI
ANDROID TRAINING IN CHENNAI |Best ANDROID TRAINING Institute IN CHENNAI
Excellent Blogs,Appreciating for this intense work and keep doing more...Learn Python to get a enormous impact in your life
ReplyDeletepython training in chennai | python training in annanagar | python training in omr | python training in porur | python training in tambaram | python training in velachery
Excellent Blogs,Appreciating for this intense work and keep doing more...Learn Python to get a enormous impact in your life
ReplyDeleteAWS training in Chennai
AWS Online Training in Chennai
AWS training in Bangalore
AWS training in Hyderabad
AWS training in Coimbatore
AWS training
very interesting stuff.thanks for sharing.Angular training in Chennai
ReplyDeleteperde modelleri
ReplyDeletesms onay
MOBİL ÖDEME BOZDURMA
Nft Nasıl Alınır
Ankara Evden Eve Nakliyat
trafik sigortası
dedektör
web sitesi kurma
aşk kitapları
Good content. You write beautiful things.
ReplyDeletemrbahis
vbet
sportsbet
mrbahis
vbet
sportsbet
hacklink
taksi
hacklink
Good text Write good content success. Thank you
ReplyDeletetipobet
kralbet
betpark
kibris bahis siteleri
slot siteleri
poker siteleri
bonus veren siteler
mobil ödeme bahis
salt likit
ReplyDeletesalt likit
dr mood likit
big boss likit
dl likit
dark likit
T7DJ
salt likit
ReplyDeletesalt likit
L8RİM