New Project
For this example I will be using Eclipse for my IDE.
- Download Eclipse IDE for Java EE Developers from http://www.eclipse.org/downloads/
- Unzip the contents in your root Eclipse folder. In my case I unzipped it in c:/java/eclipse
- Run the ‘eclipse.exe’ in [eclipse root]/eclipse
- Select a workspace location for Eclipse to store your projects. In my case I used the default location
- Click on the ‘Workbench’ icon
- Select Help -> Install New Software
- Click the ‘Add…’ button
- Name: m2eclipse
- Location: http://m2eclipse.sonatype.org/sites/m2e
- Click ‘OK’
- Check the ‘Maven Integration for Eclipse’ option
- Click ‘Next’
- Click ‘Next >’
- Select ‘I accept the terms of the license agreements’
- Click ‘Finish’
- Click ‘Restart Now’
- Select Window -> Preferences
- Add the Maven 3 location the you installed earlier
- Create a new Maven project by selecting File -> New -> Other…
- Select Maven -> Maven Project
- Check ‘Create a simple project (skip archetype selection)’
- Click ‘Next >’
- Enter Project Information
- Enter Group Id. This is the domain where the project is hosted. For example if the ‘Awesome’ project was hosted at GitHub then the Group Id would be ‘com.github.awesome’.
- Enter Artifact Id. This is the name of the resulting artifact. For example if Artifact Id is ‘awesome’ and the packaging is JAR the artifact will be named ‘awesome.jar’.
- The version can remain 0.0.1-SNAPSHOT
- Select the packaging that you desire
- Enter a Name. This name will show up in the console when you run Maven. This will also show up in the documentation that Maven generates
- Enter a Description. This is used in the documentation
- Click ‘Next >’
- Add a dependency on JUnit. One of the best features of m2eclipse plugin is the ability to search for available dependencies. (This feature does not work if you configure ‘M3_HOME’ instead of ‘M2_HOME’)
- Click ‘Finish’
- src – source and resource files
- target – compiled files, reports and generated artifacts
- main – application/library files
- test – test files
- java – java files
- resources – non java files like XML
Maven’s default package structure:
- Open the pom.xml file.
- Add the compiler plugin so you can configure your JDK version. Search for the maven-compiler-plugin.
- For this example set the JDK version to 1.6
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
- Run ‘Maven install’ to verify that the project and environment is setup correctly
- The build was successful
Project Management
Parent POM
Parent POMs are an simple way to extract common configurations and reuse them in multiple projects. We will extract the compiler plugin configuration into a parent pom.
Create a new Maven Project with a packaging type of ‘pom’.
<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.sourceallies.parent-sample</groupId>
<artifactId>parent-sample</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Parent Sample POM</name>
<description>This contains common company settings for all projects.</description>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
In the child pom file add the following
<parent>
<artifactId>parent-sample</artifactId>
<groupId>com.sourceallies.parent-sample</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
Note: Update the project configuration after you change the Java version. Right click your project -> Maven -> Update Project Configuration
Local Maven Repository
It’s a good idea for organizations to host their own local Maven repository. This provides more control over the hosting and management of project dependencies. This also provides a place to easily add third-party artifacts that may not be available in external Maven repositories.
I’m most familiar with
Archiva so I will set it up in this tutorial. Nevertheless, there are other Build Artifact Repository Management software available such as
Sonatype.
- Download and unzip Archiva
- Open a Commandline window
- Navigate to the ‘bin’ directory in the exploded Archiva directory
- Run ‘archiva.bat console’
- Setup a new Admin account
Add this repository to the ’settings.xml’ file in [Maven 3 Home]/conf. This sets Archiva as your dependency repository. Add this to the ‘mirrors’ section.
<mirror>
<id>archiva.default</id>
<url>http://localhost:8080/archiva/repository/internal/</url>
<mirrorOf>*</mirrorOf>
</mirror>
To publish your artifacts to Archiva add the following to the ’settings.xml’ file. Replace archiva-deployment-user with the Admin username (this is ‘admin’ by default) that you setup. Replace archiva-deployment-pwd withthe Admin password that you setup.
<server>
<id>archiva.internal</id>
<username>{archiva-deployment-user}</username>
<password>{archiva-deployment-pwd}</password>
</server>
<server>
<id>archiva.snapshots</id>
<username>{archiva-deployment-user}</username>
<password>{archiva-deployment-pwd}</password>
</server>
Add the following to the parent pom in the ‘parent-sample’ project. This tells your project where to publish it’s artifacts.
<distributionManagement>
<repository>
<id>archiva.internal</id>
<name>Internal Release Repository</name>
<url>http://localhost:8080/archiva/repository/internal/</url>
</repository>
<snapshotRepository>
<id>archiva.snapshots</id>
<name>Internal Snapshot Repository</name>
<url>http://localhost:8080/archiva/repository/snapshots/</url>
</snapshotRepository>
</distributionManagement>
Since the ‘distributionManagement’ information was modified you need to first run ‘mvn clean install’ on the ‘parent-example’ project. Then run ‘mvn clean deploy’ on the ‘example’ project. This will download the dependencies to the local Archiva dependency repository and publish the ‘example.jar’ to Archiva.
Multiple Artifacts from a Single Source
Maven restricts projects to one artifact per ‘pom’ file. While we can argue whether this is the right approach, there is a simple solution. If you have a project called ’sample-service’ that produces a WAR and you want to create a JAR from the same source code then you need to create a second package containing a single pom file.
|_sample-service
|_src
|_pom.xml
|_sample-client
|_pom.xml
<configuration>
<sources>
<source>**/src/main/java/**</source>
<source>**/src/main/resources/**</source>
</sources>
</configuration>
Release Plugin
This is a very powerful plugin. If you’ve ever released a project by hand you will appreciate this plugin. One of my favorite features is that it checks to see if all of the dependencies refer to released versions. Without this automatic check you are forced to search through all of the dependency management configurations for unreleased dependencies. Depending on the size of your hierarchy this can be quite painful.
Along with this dependency check it also runs all of the tests, tags the code with the release name, and publishes the artifacts in the Maven repository. This plugin embodies the best standards for releasing within our industry. Standards that I easily forget and/or mess up. I highly recommend that you use this plugin to release your projects. Please refer to
http://maven.apache.org/plugins/maven-release-plugin for more information.
Aggregate POM
An aggregate POM joins multiple modules together.
_pom.xml (aggregate)
|_sample-service
|_pom.xml (module 1)
|_sample-client
|_pom.xml (module 2)
The aggregate pom configures multiple modules in the modules section.
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>sample-app</artifactId>
<version>1</version>
<packaging>pom</packaging>
<modules>
<module>sample-service</module>
<module>sample-client</module>
</modules>
</project>
When you execute a Maven command at the aggregate level it will execute the same command on all of the configured modules. If any of these modules depends on another module Maven builds them in the correct order. This is a simple way to break up a large project into focused modules without loosing a coordinated project management strategy. While this could be replicated with Ant and Ivy it would be painful to configure and maintain. Aggregate projects are first class citizens in Maven.
Dependency Management
The ‘dependencymanagement’ section defines the acceptable versions for a project. This configuration does not result in a JAR being downloaded and included in the project. On the other hand, this is a directive specifying which version of a dependency should be used if a project depends on it. This is a simple way to force Maven to select a specific dependency version. In the case of an aggregate project it is best to add this to the aggregate pom. Configure the dependency versions in one place for all of the modules.
<dependencyManagement>
<dependencies>
<dependency>
<groupId>test</groupId>
<artifactId>a</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>test</groupId>
<artifactId>b</artifactId>
<version>1.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>test</groupId>
<artifactId>c</artifactId>
<version>1.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>test</groupId>
<artifactId>d</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
</dependencyManagement>
Distribution Zip
Maven provides a simple way to package all of your artifacts in a single zip file. This simplifies the deployment process and increases traceability. For example I have used this feature to package my WAR, SQL, and external PDF files in the same zip file. Our deployment team extracted the WAR and PDF files and deployed them. Then they passed the SQL on to the DBA’s to run the scripts. All of the files necessary to deploy our project were packaged together and published to our Maven repository. Please refer to
http://maven.apache.org/plugins/maven-assembly-plugin for more information.