How do I make my first Maven project?
We are going to jump headlong into creating your first Maven project! To create our first Maven project we are going to use Maven's archetype mechanism. An archetype is defined as an original pattern or model from which all other things of the same kind are made. In Maven, an archetype is a template of a project which is combined with some user input to produce a working Maven project that has been tailored to the user's requirements. We are going to show you how the archetype mechanism works now, but if you would like to know more about archetypes please refer to our Introduction to Archetypes .
On to creating your first project! In order to create the simplest of Maven projects, execute the following from the command line:
Once you have executed this command, you will notice a few things have happened. First, you will notice that a directory named my-app has been created for the new project, and this directory contains a file named pom.xml that should look like this:
pom.xml contains the Project Object Model (POM) for this project. The POM is the basic unit of work in Maven. This is important to remember because Maven is inherently project-centric in that everything revolves around the notion of a project. In short, the POM contains every important piece of information about your project and is essentially one-stop-shopping for finding anything related to your project. Understanding the POM is important and new users are encouraged to refer to the Introduction to the POM .
This is a very simple POM but still displays the key elements every POM contains, so let's walk through each of them to familiarize you with the POM essentials:
- project This is the top-level element in all Maven pom.xml files.
- modelVersion This element indicates what version of the object model this POM is using. The version of the model itself changes very infrequently but it is mandatory in order to ensure stability of use if and when the Maven developers deem it necessary to change the model.
- groupId This element indicates the unique identifier of the organization or group that created the project. The groupId is one of the key identifiers of a project and is typically based on the fully qualified domain name of your organization. For example org.apache.maven.plugins is the designated groupId for all Maven plug-ins.
- artifactId This element indicates the unique base name of the primary artifact being generated by this project. The primary artifact for a project is typically a JAR file. Secondary artifacts like source bundles also use the artifactId as part of their final name. A typical artifact produced by Maven would have the form <artifactId>-<version>.<extension> (for example, myapp-1.0.jar ).
- packaging This element indicates the package type to be used by this artifact (e.g. JAR, WAR, EAR, etc.). This not only means if the artifact produced is JAR, WAR, or EAR but can also indicate a specific lifecycle to use as part of the build process. (The lifecycle is a topic we will deal with further on in the guide. For now, just keep in mind that the indicated packaging of a project can play a part in customizing the build lifecycle.) The default value for the packaging element is JAR so you do not have to specify this for most projects.
- version This element indicates the version of the artifact generated by the project. Maven goes a long way to help you with version management and you will often see the SNAPSHOT designator in a version, which indicates that a project is in a state of development. We will discuss the use of snapshots and how they work further on in this guide.
- name This element indicates the display name used for the project. This is often used in Maven's generated documentation.
- url This element indicates where the project's site can be found. This is often used in Maven's generated documentation.
- description This element provides a basic description of your project. This is often used in Maven's generated documentation.
For a complete reference of what elements are available for use in the POM please refer to our POM Reference. Now let's get back to the project at hand.
After the archetype generation of your first project you will also notice that the following directory structure has been created:
As you can see, the project created from the archetype has a POM, a source tree for your application's sources and a source tree for your test sources. This is the standard layout for Maven projects (the application sources reside in $
If you were to create a Maven project by hand this is the directory structure that we recommend using. This is a Maven convention and to learn more about it you can read our Introduction to the Standard Directory Layout .
Now that we have a POM, some application sources, and some test sources you are probably asking.
How do I compile my application sources?
Change to the directory where pom.xml is created by archetype:generate and execute the following command to compile your application sources:
Upon executing this command you should see output like the following:
The first time you execute this (or any other) command, Maven will need to download all the plugins and related dependencies it needs to fulfill the command. From a clean installation of Maven, this can take quite a while (in the output above, it took almost 4 minutes). If you execute the command again, Maven will now have what it needs, so it won't need to download anything new and will be able to execute the command much more quickly.
As you can see from the output, the compiled classes were placed in $
Now, this is simply to compile a single tree of application sources and the Ant script shown is pretty much the same size as the POM shown above. But we'll see how much more we can do with just that simple POM!
How do I compile my test sources and run my unit tests?
Now you're successfully compiling your application's sources and now you've got some unit tests that you want to compile and execute (because every programmer always writes and executes their unit tests *nudge nudge wink wink*).
Execute the following command:
Upon executing this command you should see output like the following:
Some things to notice about the output:
- Maven downloads more dependencies this time. These are the dependencies and plugins necessary for executing the tests (it already has the dependencies it needs for compiling and won't download them again).
- Before compiling and executing the tests Maven compiles the main code (all these classes are up to date because we haven't changed anything since we compiled last).
Now that you can compile your application sources, compile your tests, and execute the tests, you'll want to move on to the next logical step so you'll be asking.
How do I create a JAR and install it in my local repository?
Making a JAR file is straight forward enough and can be accomplished by executing the following command:
If you take a look at the POM for your project you will notice the packaging element is set to jar. This is how Maven knows to produce a JAR file from the above command (we'll talk more about this later). You can now take a look in the $
Now you'll want to install the artifact you've generated (the JAR file) in your local repository (
/.m2/repository is the default location). For more information on repositories you can refer to our Introduction to Repositories but let's move on to installing our artifact! To do so execute the following command:
Upon executing this command you should see the following output:
Note that the surefire plugin (which executes the test) looks for tests contained in files with a particular naming convention. By default the tests included are:
And the default excludes are:
You have walked through the process for setting up, building, testing, packaging, and installing a typical Maven project. This is likely the vast majority of what projects will be doing with Maven and if you've noticed, everything you've been able to do up to this point has been driven by an 18-line file, namely the project's model or POM. If you look at a typical Ant build file that provides the same functionality that we've achieved thus far you'll notice it's already twice the size of the POM and we're just getting started! There is far more functionality available to you from Maven without requiring any additions to our POM as it currently stands. To get any more functionality out of our example Ant build file you must keep making error-prone additions.
So what else can you get for free? There are a great number of Maven plug-ins that work out of the box with even a simple POM like we have above. We'll mention one here specifically as it is one of the highly prized features of Maven: without any work on your part this POM has enough information to generate a web site for your project! You will most likely want to customize your Maven site but if you're pressed for time all you need to do to provide basic information about your project is execute the following command:
There are plenty of other standalone goals that can be executed as well, for example:
This will remove the target directory with all the build data before starting so that it is fresh.
Perhaps you'd like to generate an IntelliJ IDEA descriptor for the project?
This can be run over the top of a previous IDEA project - it will update the settings rather than starting fresh.
Note: some familiar goals from Maven 1.0 are still there - such as jar:jar. but they might not behave like you'd expect. Presently, jar:jar will not recompile sources - it will simply just create a JAR from the target/classes directory, under the assumption everything else had already been done.
How do I use plug-ins?
Whenever you want to customise the build for a Maven project, this is done by adding or reconfiguring plugins.
Note for Maven 1.0 Users: In Maven 1.0, you would have added some preGoal to maven.xml and some entries to project.properties. Here, it is a little different.
For this example, we will configure the Java compiler to allow JDK 5.0 sources. This is as simple as adding this to your POM:
You'll notice that all plugins in Maven 2.0 look much like a dependency - and in some ways they are. This plugin will be automatically downloaded and used - including a specific version if you request it (the default is to use the latest available).
The configuration element applies the given parameters to every goal from the compiler plugin. In the above case, the compiler plugin is already used as part of the build process and this just changes the configuration. It is also possible to add new goals to the process, and configure specific goals. For information on this, see the Introduction to the Build Lifecycle .
To find out what configuration is available for a plugin, you can see the Plugins List and navigate to the plugin and goal you are using. For general information about how to configure the available parameters of a plugin, have a look at the Guide to Configuring Plug-ins .
How do I add resources to my JAR?
Another common use case that can be satisfied which requires no changes to the POM that we have above is packaging resources in the JAR file. For this common task, Maven again relies on the Standard Directory Layout. which means by using standard Maven conventions you can package resources within JARs simply by placing those resources in a standard directory structure.
You see below in our example we have added the directory $
So you can see in our example that we have a META-INF directory with an application.properties file within that directory. If you unpacked the JAR that Maven created for you and took a look at it you would see the following:
As you can see, the contents of $
To add resources to the classpath for your unit tests, you follow the same pattern as you do for adding resources to the JAR except the directory you place resources in is $
In a unit test you could use a simple snippet of code like the following to access the resource required for testing:
How do I filter resource files?
Sometimes a resource file will need to contain a value that can only be supplied at build time. To accomplish this in Maven, put a reference to the property that will contain the value into your resource file using the syntax $<<property name>>. The property can be one of the values defined in your pom.xml, a value defined in the user's settings.xml, a property defined in an external properties file, or a system property.
To have Maven filter resources when copying, simply set filtering to true for the resource directory in your pom.xml :
You'll notice that we had to add the build. resources. and resource elements which weren't there before. In addition, we had to explicitly state that the resources are located in the src/main/resources directory. All of this information was provided as default values previously, but because the default value for filtering is false, we had to add this to our pom.xml in order to override that default value and set filtering to true.To reference a property defined in your pom.xml, the property name uses the names of the XML elements that define the value, with "pom" being allowed as an alias for the project (root) element. So $ refers to the name of the project, $ refers to the version of the project, $ refers to the final name of the file created when the built project is packaged, etc. Note that some elements of the POM have default values, so don't need to be explicitly defined in your pom.xml for the values to be available here. Similarly, values in the user's settings.xml can be referenced using property names beginning with "settings" (for example, $
To continue our example, let's add a couple of properties to the application.properties file (which we put in the src/main/resources directory) whose values will be supplied when the resource is filtered:
With that in place, you can execute the following command (process-resources is the build lifecycle phase where the resources are copied and filtered):
and the application.properties file under target/classes (and will eventually go into the jar) looks like this:
To reference a property defined in an external file, all you need to do is add a reference to this external file in your pom.xml. First, let's create our external properties file and call it src/main/filters/filter.properties :