Background on My Use of Maven

A few years ago I made the transition from using Ant for my Java project builds to the mostly wonderful world of Maven. In Maven's previous incarnation there were many issues in using the tool. One of the major points of contention was Jelly and it's executable XML model. Most of the benefits outweighed these issues in my use of Maven. The benefits included good dependency management, a strong project structure, easy to integrate plugins, great reporting facilities, and the ultimate dashboard for viewing all pertinent project information.

One large problem that Maven 1.x had was the learning curve. With Ant, many developers had direct access, similar to their programming tools and environments, to launching functions or “targets”. Ant provided a relatively simple set of targets which provided an usable API for developing complex build scripts. I was a heavy user of Ant for quite a few years before I came across Maven. For me, Ant did the job of building and providing valuable details for my projects better than makefiles but there was a catch. In order to make my build environment extendable I would have to provide a large amount of indirection without a nice IDE to help swallow the cost of maintaining my scripts. The Ant builds that I created, and those that were created by others in projects I worked on for that matter, started to get broken up into multiple files with interesting property file loading mechanmisms. Not only that, each project had it's own way of solving the build script bloat which created a large cost in knowledge transfer and maintenance.

Then Maven came along. Most of the extra targets I had been creating to generate reports on my unit tests, code statistics, and documentation were now just plugins that I could integrate into my Maven artifacts. There were only two files that I needed, project.xml and project.properties, unless I needed to extend Maven in which case I added functions or “goals” to a maven.xml file. All of the plugins had access to the data which was present in your POM (project object model). This data included source control management, project developers, versions, issue tracking URL, and other project detail information. The fact that running these goals were slower than my previous Ant scripts was overshadowed by the fact that I could run `maven eclipse` and import my project into Eclipse IDE. Also, I no longer had to think about how to check jar archives into my source repository so that I did not fill up the file system since the source control management had no way to diff binary files.

Of course, Maven 1.x had quite a few warts which is to be expected for a 1.x release. I found ways to work around many impediments but it always got the job done. And then there was the release of Maven 2.0 and my expectations jumped up a few notches. On my first day of using Maven 2.0 I could see how this upgrade was going to make my life even easier. Now there was only one file to put all of my project details into, pom.xml. I had created a plugin for Jini in the Maven 1.x plugin paradigm already. This creation of this plugin had me up late on many an evening for two weeks. I finished but not without some heavy ground to air attacks on Jelly. This made me a bit hesitant to upgrade the plugin to Maven 2.0. One weekend night I made the decision to go forward with the upgrade. To my astonishment, I was finished with the upgrade by Sunday night and it was just plain old Java development. What a nice surprise.

Now to the Good Part

In order to create a new plugin project with Maven 2.0, you can use the “mojo” archetype by issuing the following command:

mvn archetype:create -DarchetypeGroupId=org.apache.maven.archetypes \
    -DarchetypeArtifactId=maven-archetypes \
    -DarchetypeVersion=1.0-alpha3 \
    -DgroupId=com.mybusinessname.maven.plugin \
    -DartifactId=mymojoprojectname

This command can be broken down into the plugin goal for archetype execution, the specific archetype to use, and the new plugin's project information. The plugin goal to execute for archetypes is “archetype:create” which is reference to a plugin called “archetype” which has a goal called “create”. Upon execution, the “create” goal looks for some information about where to get the archetype artifacts for generating a new project. This information is contained within the property values for “archetypeGroupId”, “archetypeArtifactId”, and “archetypeVersion”. This information describes how to find the archetype inside a Maven repository to download and use in the execution process. Finally, the “groupId” and “artifactId” property values describe the namespace and the project name to use when generating the new project directory structure. In this case, a directory called “mymojoprojectname” would be created in the current directory and the groupId would be used as the package name in the Java files and as the groupId inside your pom.xml.

Now that we have a new project created we can run the following to install our plugin inside our local Maven repository, which is usually located inside your home directory under “.m2/repository”:

mvn install

This should create a jar file named “mymojoprojectname-1.0-SNAPSHOT.jar” inside the target directory which was generated during the execution of the “install” build lifecycle. The jar will also be copied into your local Maven repository location under the “${HOME}/.m2/repository/com/mybusinessname/maven/plugin/mymojoprojectname/1.0-SNAPSHOT/” directory. As you can see, the “groupId” property was expanded into a directory structure in which the artifacts are placed.

Now that you have successfully built your plugin which does not do anything which you intend it to do, we can modify the plugin by modifying the MyMojo.java class which is now located in the “src/main/java/com/mybusinessname/maven/plugin/” directory. As you can see, the main source directory for Maven 2.0 suggested structure is the “src/main/java” directory. Inside of that, the “groupId” property value was again expanded into the package directory structure for the plugin source. Since I use Eclipse IDE for my Java development I am inclined to use the Eclipse plugin which is executed against my new plugin project running the following command:

mvn eclipse:eclipse

This will generate the Eclipse IDE project files “.classpath” and “.project” which makes my project easily importable. Once I have executed this command, go into your Eclipse IDE and import and existing project into your workspace from the project directory. If you have not setup your Eclipse environment to work with Maven 2.0 before you will have to add a classpath variable called “M2_REPO” into your IDE preferences. Select “Window->Preferences” from the main menu. Drill down the left side tree in the dialog to “Java->Build Path->Classpath Variables”. Click the “New” button and enter “M2_REPO” into the name field and “${HOME}/.m2/repository” into the path field where “${HOME}” is your environment's home directory such as “C:\Documents and Settings\{username}” on Windows and “/home/{username}” on *nix. When you are finished entering this in your workspace should rebuild your projects if you have “build automatically” selected in your IDE preferences.

Under the “src/main/java” source folder in Eclipse you will find a package named “com.mycompanyname.maven.plugin” with a class named “MyMojo” inside. Open the MyMojo class in your Java editor and you should see only one method which is implemented from the abstract superclass AbstractMojo called “execute()” which looks something like this:

package com.mycompanyname.maven.plugin;
...
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
/**
 * Goal which touches a timestamp file.
 *
 * @goal touch
 *
 * @phase process-sources
 */
public class MyMojo extends AbstractMojo
{
    /**
     * Location of the output directory.
     * @parameter expression="${project.build.directory}"
     * @required
     */
    private File outputDirectory;
    public void execute() throws MojoExecutionException {
        ...
    }
}

Also, you'll notice the class contains some private class variables which are declared as parameters to your new plugin by the inclusion of the “@parameter” tag inside the javadoc comment for each variable. Now that you are ready to work on the details of your plugin, I will guide you to the developing Java plugins documentation on the Maven web site. This will give more information about modifying your Mojo.

Conclusion

Maven is not only a developer's build tool. It provides a mechanism for distributing information about your project easily to external viewers such as project managers, customers, and IT management. I see this as a direct benefit to developers since they no longer have continuous conversations with these parties since the information is usually made available through continuous integration systems or generated project dashboards. However, Maven does provide great facilities to solve project configuration management issues in a consistent and manageable manner across all of your projects which use it. I hope that if you choose to use Maven in your projects that you will find it an incredibly valuable tool.