About this Guide

The Maven User Guide is intended to help developers get acquainted with Maven by providing thorough descriptions and examples. If you have any suggestions or comments please feel free to post them to the Maven users' list.

Thanks for choosing Maven!

Introduction

Maven was originally started as an attempt to simplify the build processes in the Jakarta Turbine project. There were several projects each with their own Ant build files that were all slightly different and JARs were checked into CVS. We wanted a standard way to build the projects, a clear definition of what the project consisted of, an easy way to publish project information and a way to share JARs across several projects.

What resulted is a tool that can now be used for building and managing any Java-based project. We hope that we have created something that will make the day-to-work work of Java developers easier and generally help with the comprehension of any Java-based project.

The Project Object Model

Maven is based on the concept of a project object model (POM) in that all the artifacts produced by Maven are a result of consulting a well defined model for your project. Builds, documentation, source metrics, source cross-references and anything else that may be provided by a Maven plug-in are all controlled by your POM.

POM Processing

This document outlines how the POM is processing during Maven execution. Some simple forms of POM inheritance are shown, and the interpolation mechanism is demonstrated.

POM Interpolation

The POM, in its familiar project.xml form, is now processed as a Jelly script. In the majority of cases users won't care that the project.xml is really a Jelly script under the covers but it does allow the use interpolated values if you wish. I would rather not see logic start cropping up in project.xml files but the flexibility is there now that the project.xml file is a stealth Jelly script :-) Below is an example of what you can do:

        

POM Inheritance

There is now a simple form of inheritance available for use when using the POM in its familiar project.xml form. Below is an example of what you can do:

Currently the resolution of the parent is fairly dumb and there hasn't been any testing beyond a single level of extension. But even this level of extension coupled with interpolation can potentially buy you a lot. The motivation for this was an attempt at simplifying building for the commons.

You could define something like this for the master template:

And for a child you could have something like this:

And what you will get is the child's ${pom.artifactId} value substituted into the parent template. So for projects like the commons where you have many builds that are basically set up the same way you can use a master template and leave very little in the child's project.xml file.

This should also make it easier to deal with a single project producing multiple JAR artifacts. I plan to test the inheritance out in the commons now as the project.xml won't interfere with the standard Ant builds.

If you're wondering what the DVSL reports will look like using this mechanism then you're on the ball! I have changed the DVSL reporting to work on the POM itself i.e. the DVSL transformation is performed on a Java object. This was necessary in order for reports to come out correctly when interpolation and inheritance are involved. You can't use the child template listed above and expect it to work. We need to use the fully resolved POM. As far as I can tell this is working. The process I'm using is probably not the most efficient but it can be improved and we'll probably break even because the POM is processed only once now (that's the theory anyway, I might missed a few bits) and can be used everywhere, or at least that's what I tried to do in this pass.

If you don't use inheritance or interpolation then everything should work as per usual. The maven site itself is looking ok and the last few sites deployed have used what I'm going to commit later tonight.

Using Plug-ins

Maven is in essence a small core that works with a satellite of plug-ins. All functionality provided by Maven is done so in the form of plug-ins.

maven.xml

The file maven.xml in your project is a 'special' file that Maven looks for during processing.

This file is the place that you can add extra processing to the Maven build, or attach your own code before or after a Maven 'goal', such as jar or test is executed.

Maven uses Jelly as it's scripting language, and any valid jelly tags can be placed in the maven.xml.

The goal functionality Maven uses is provided by the werkz tag library that is built into werkz. For more information, see this wiki page.

Sample maven.xml

Note the sample file below is expected to fail, as Maven doesn't define a 'compile' goal by default.

Here's the sample maven.xml

You'll notice that there are a few items here and we'll explain them in order of appearance.

The project element

The project element, <project>, is the root element for any maven.xml file.

The project element specifies a default attribute, default="nightly-build", that tells Maven to attain the nightly-build goal if the user simply executes maven with no arguments

The default attribute is followed by several XML namespace declarations, e.g.

  1. xmlns:j="jelly:core"

    This tells Jelly that all XML elements prefixed with j: are part of the predefined tag library registered with jelly under the identifier core

  2. xmlns:u="jelly:util"

    This tells Jelly that all XML elements prefixed with u: are part of the predefined tag library registered with jelly under the identifier util.

Any Jelly tag library you want to use in your maven.xml must be declared in the project element and given a namespace prefix

Maven pre-registers the jeez tag library with an empty prefix. This tag library groups the ant and werkz tag libraries into one namespace. This allows Maven scripts to use any werkz or ant tag with no XML namespace, and makes migrating from ant a simple process.

Goals

A goal is a werkz tag similar in nature to an Ant target; it's a named container for a set of tags to be executed.

Since the jeez tag library is pre-registered by maven, a goal may include any valid Ant tag in it's body.

To execute a goal defined in your maven.xml, you simply provide the goal name to Maven from the command prompt. To execute the nightly-build defined in our sample, you would use:

maven nightly-build

Maven plugins prefix the goals they define with the plugin name, so that they wont clash with your goals, e.g. jar:jar is the goal defined by the jar plugin to create a jar file from your project

Jelly coding

Inside of each goal, there are Jelly tags that you provide to perform functionality. Let's look at the code from our sample

set

This line is a jelly core tag, as it is using the j: prefix defined in the project element, called set.

The set tag sets the jelly variable named by the var attribute to the value given by the value attribute. Unlike Ant properties, Jelly variables can be changed once they have been given a value.

mkdir

This executes the Ant task mkdir, which simply creates a directory. The directory is specified using a variable, ${maven.build.dir}

tokenize

This executes the Jelly tokenize tag. The tag is found in the Jelly predefined util tag library as per the u: prefix defined on the project element.

The tokenize tag will tokenize the contents of it's body into a list for later processing.

  • The var attribute is the variable that will be assigned the new list.
  • The delim attribute is the delimiter used to separate items in the string
  • The body of the tokenize tag in this case is a variable, goals, set a couple of lines previously, which contains compile and test separated by commas

forEach

The forEach tag provides a simple loop facility. It executes it's body each time through the loop.

  • The items attribute is an expression that is evaluated to get the the collection to be iterated through
  • The var attribute specifies the variable to place each item in, as the collection is processed. The variable is available to the forEach body.
  • The indexVar attribute specifies the variable to place a counter of the number of elements (zero-based) processed

The body of the forEach tag outputs some text about the goal and the number being processed and attempts to attain that goal using the attainGoal werkz tag.

Maven Setup

Properties Processing

The properties files in Maven are processed in the following order:

  • ${project.home}/project.properties
  • ${project.home}/build.properties
  • ${user.home}/build.properties

Where the last definition wins. So, Maven moves through this sequence of properties files overridding any previously defined properties with newer definitions. In this sequence your ${user.home}/build.properties has the final say in the list of properties files processed. We will call the list of properties files that Maven processes the standard properties file set.

In addition, System properties are processed after the above chain of properties files are processed. So, a property specified on the CLI using the -Dproperty=value convention will override any previous definition of that property.

Plug-in Properties

Plug-ins are loaded after the above sequence of properties files are processed but the PluginManager is instructed not to override values that have been previously set. This works in the opposite way of Maven's normal properties processing because the Plug-ins can only be processed after the rest of Maven's internals are initialized but we want it to appear like:

  • Plug-in default properties are processed
  • ${project.home}/project.properties are processed
  • ${project.home}/build.properties are processed
  • ${user.home}/build.properties are processed

So even though Plug-ins are processed later in the initialization cycle you can override a plug-in's default properties as you can with any other property. For example, the Checkstyle plug-in defines the following default property:

Which, as you might guess, tells the Checkstyle plug-in to use Sun's coding conventions as the default format. But you can override this value in any of the files in standard properties fileset. So if in your ${project.home}/project.properties you place the following value:

Then the Checkstyle plug-in will use Turbine's coding conventions.

Behavioural Properties

The following is a list of properties that change the way Maven works.

PropertyDescriptionDefault Value
maven.build.dest The directory where generated classes go. ${maven.build.dir}/classes
maven.build.dir The directory where generated output, e.g. class files, documentation, unit test reports etc goes

CAUTION: Changing default maven.build.dir value in your ${user.home}/build.properties might allow one some control of individual project directory layouts. However this practice will interfere with the bootstrap of Maven from source code, as it expects the jar created to be in ${basedir}/target/

${basedir}/target
maven.build.src The directory where generated source goes. ${maven.build.dir}/src
maven.conf.dir The directory that holds configuration files ${basedir}/conf
maven.docs.dest The output directory for the generated html from reports. ${maven.build.dir}/docs
maven.docs.omitXmlDeclaration Whether generated documentation should have an xml declaration, e.g.
<?xml version="1.0"?>
false
maven.docs.outputencoding The character encoding for generated documentation ISO-8859-1
maven.docs.src The directory for user supplied documentation. ${basedir}/xdocs
maven.gen.docs The directory where generated xdocs that need to be transformed to html are placed. ${maven.build.dir}/generated-xdocs
maven.home.local The directory on the local machine maven uses to write user specific details to such as expanded plugins and cache data. ${user.home}/.maven
maven.mode.online Whether you are connected to the internet or not. true
maven.plugin.dir Where maven can find it's plugins ${maven.home}/plugins
maven.plugin.user.dir Where maven can find plugins for this user only. ${maven.home.local}/plugins
maven.plugin.unpacked.dir Where maven expands installed plugins for processing. ${maven.home.local}/cache
maven.repo.central This is the host that Maven will attempt to deploy the distribution to during a dist:deploy. login.ibiblio.org
maven.repo.central.directory This is the directory that Maven will copy the distribution to during a dist:deploy. /public/html/maven
maven.repo.local The repository on the local machine maven should use to store downloaded artifacts (jars etc). ${maven.home.local}/repository
maven.repo.remote The repository maven should use to download artifacts (jars etc) that it can't find in the local repository http://www.ibiblio.org/maven
maven.repo.remote.enabled Whether or not a remote repository should be used. true
maven.scp.executable The executable to use for secure copies scp
maven.src.dir The base directory for source code. ${basedir}/src
maven.ssh.executable The executable to use for executing commands remotely ssh

Using Proxies

If you only have access via a proxy then Maven obeys the following properties.

Proxy PropertiesDescription
maven.proxy.host The IP or address of your proxy.
maven.proxy.port The port number of your proxy.
maven.proxy.username User name if your proxy requires authentication.
maven.proxy.password Password if your proxy requires authentication.
maven.proxy.ntlm.host The host to use if you are using NTLM authentication.
maven.proxy.ntlm.domain The NT domain to use if you are using NTLM authentication.

If you do require a proxy, the most appropriate place to set these values would be in your ${user.home}/build.properties file.

Using Multiple Remote Repositories

You can specify the use of multiple remote repositories in any of the properties files processed by Maven by using something like the following:

Project Setup

Starting a New Project

If you using Maven for the first time or starting a new project you can use the GenApp plugin to automate the creation of a Maven project tree.

When you execute this command you will see something like the following:

When the command finishes executing you should have a complete project tree that looks something like the following:

Building

Maven works using the notion of a central repository. All artifacts required for building are drawn from the central repository. Currently our central repository is housed here at Ibiblio. In a typical Maven project, the JARs required to build a are pulled from the central repository. Maven will only retrieve dependencies which are not satisfied. If you are using Maven to build several projects it is likely that those projects share a few dependencies: Maven will let you share one JAR file between any number of projects that require that JAR to build. No multiple copies of the same JAR on your system!

Build Lifecycle

Storing JARs in CVS

It is not recommended that you store your JARs in CVS. Maven tries to promote the notion of a user local repository where JARs, or any project artifacts, can be stored and used for any number of builds. Many projects have dependencies such as XML parsers and standard utilities that are often replicated in typical Ant builds. With Maven these standard utilities can be stored in your local repository and shared by any number of builds.

Overriding Stated Dependencies

You may find it convenient, or necessary, at times to override the dependencies stated in a given POM. You may wish to use JAR artifacts somewhere in the filesystem or you may wish simply to override the stated version of a given JAR artifact. For this Maven provides the a an easy way for you to select which artifacts you want to use for building. It is highly recommended that you set up your own local repository: but in cases where expediency is a concern, or you are migrating from an Ant build the JAR override feature may come in handy.

In order to use the JAR override feature, you must set the maven.jar.override property on. Once this property is set you can specify JAR override directives in any of the properties files that maven processes.

There are two type of JAR override directives. The first form allows you to specify a specific JAR artifact path for a given artifactId; the second allows you to specify a specific version of a JAR artfact that exists in your local repository. The two forms are as follows:

Below is an example of what a properties file might look like that contains JAR override directives:

Using SNAPSHOT Dependencies

In Maven SNAPSHOTs are artifacts aproximate the latest build of a particular project. If a project that you depend on is changing frequently you can state in your POM that you wish to try and keep up with that project by declaring it a SNAPSHOT dependency. So, for example, you may be trying to stay abreast of changes in Jelly so you might put the following in your POM:

This tells Maven that you are always looking to use the latest build of Jelly that is available in the Maven repository. Internally to Maven SNAPSHOT dependencies are always considered failed dependencies. That being the case Maven will always try to retrieve a copy of SNAPSHOT dependency from the Maven repository. If you are working offline Maven will warn you that your SNAPSHOT dependencies may be out of date.

Multi Project Builds and the Reactor

With Maven the Reactor is the tool that is used to control multi project builds. The Reactor uses the Werkz package to determine the correct build order from the dependencies stated by each project in their respective POMs. The Reactor was created to encourage the creation, or refactoring, of projects into smaller, discrete, more coherent units. The Reactor is ideal for Component Oriented Programming (COP) where the overall system is comprised of many discrete entities that need to be aggregated to form a whole for deployment.

The Reactor can execute an arbitrary list of goals for any set of specified projects. So while the Reactor was created for building, it can be used for things like site generation, or any sort of artifact generation.

Currently the db.apache.org site is generated by collecting project information from all its subprojects and injecting the harvested information into a set of Velocity templates which are processed by the Jelly Velocity Tag Library. You can browse the mechanism used here.

In Plexus, an Avalon-based container, the component manifest which tracks all Plexus components is generated by walking over all of the components, harvesting the information and aggregating it into a single manifest. Again we use Velocity templates and the Jelly Velocity Tag Library. You can browse the mechanism used here.

Here is an example of how you might use the Reactor Tag to process a set of components where the site is generated

If you have to generate documentation for N projects with an overall front-end do look at the db.apache.org site as the navigation, mailing lists, committer lists and source repository lists are all harvested from sub-projects to produce the overall site. This means that the redundant, error prone process of moving sub-project specific information to the overall site is removed. Sub-projects at db.apache.org take care of their own information and it finds its way to the top-level site automatically.

Building Offline

If you find you need to build your projects offline you can either use the offline switch on the CLI:

which is equivalent to

Or you can set maven.mode.online to false in a property file.

In online mode, maven always downloads SNAPSHOT dependencies, see Using SNAPSHOT Dependencies. If the snapshots in your local repository are younger than the ones on the server, you propably don't want that maven overwrites you local snapshot jars. To avoid downloading, set property

In maven beta 9, this property does not work (but it's fixed in newer releases). Clearing the property maven.repo.remote by setting

via CLI or property file has the same effect.

Using maven.repo.remote.enabled=false and maven.mode.online=true is the combination to use if one needs a working "-link" option for the javadoc plugin plus no download of snapshot/any jars.

Summary of CLI Options

If you are using the commandline (CLI) to build, here is a quick summary of the options available:

Testing

Test Resources

It is a fairly common occurrence that you want to include some resources in your test classpath for testing purposes. Maven allows you include any arbitrary set of resources for testing by utilizing the project/build/unitTest/resources element in your POMs.

The following example demonstrates how to recursively include all files with an 'xml' or 'properties' extension within the ${basedir}/src/test directory:

The following example demonstrates how to recursively include all files with an 'xml' or 'properties' extension within the ${basedir}/src/test directory and exclude the naughty.properties file. Note the addition of the project/build/unitTest/resources/excludes element:

Running a Single Test

To run a single test use something like the following:

Packaging

JAR Resources

Deploying

Resolving SNAPSHOT Dependencies

It is convenient to use SNAPSHOT dependencies while developing but when you deploy you need to resolve all your SNAPSHOT dependencies so that your releases consist of all immutable artifacts. If you release a project with SNAPSHOT dependencies and some of the SNAPSHOTs change after your release you could wind up very quickly with a release that doesn't work.

When SNAPSHOTs are deployed in Maven a timestamped version for the artifact being deployed is created. So Maven would know that foo-SNAPSHOT.jar actually refers to foo-20030101.010101.jar in the Maven Repository. When it comes time to deploy you can ask Maven to convert your SNAPSHOT versions into timestamped versions using the following command:

You will be presented with an interactive console where you can choose which SNAPSHOT dependencies you want to resolve. When this process is complete Maven will write out your POM with your modified dependency entries.

If you wish Maven just to simply do its best at resolving SNAPSHOT dependencies you can use the following command:

Copying Dependency JARs

The easiest way to copy your project' dependency JARs is to use something like the following sample maven.xml file as a guide:

Using the deploy:copy-deps tag you can easily place your project's dependency JARs where you wish. If you wish to exclude certain dependency JARs you can provide a list of dependency ids and each dependency listed will be excluded from the copy:

Naming Conventions

This section outlines the naming conventions used in the Maven project object model (POM). This document is an attempt to try and unify the many various ways projects name the artifacts that they publish for general consumption by the Java developer community.

Rules and Guidelines

Projects

A project must have a unique identifier that is comprised of lowercase letters [a-z] where hyphens can be used. The unique id must also start with a lowercase letter [a-z]:

All references from one project to another are to be made in terms of the unique group id and artifact id. At the moment the only place in the POM where this is relevant is the declaration of project dependencies which is discussed below.

A project should have a human readable name that can be used in documentation.

A project should have a group identifier. This group identifier is the basis for the name

All artifacts published by a project should be based on the project's unique identifier and placed in a directory based on the project's group identifier. So for the above entry, assuming an artifact type of jar, we might have something that looks like the following:

Dependencies

An example of an ideal, the hopefully typical, dependency declaration looks like the following:

So, the project bar which depends on version 1.0 of the artifact with an id of foo which belongs to the group with an id of org.foo.bar. This dependency resolves to a JAR file that is stored in the local repository. The above entry assumes that the published artifact name is based on the artifactId. So for the above dependency entry Maven will assume a JAR name of foo-1.0.jar.

As user's have noticed, this ideal situation doesn't work in all cases for all projects. There are several situations that have to be accounted for which require modifications of the ideal dependency declaration:

  • The project id is not used as the base name of the published JAR e.g. the Xerces products where xercesImpl is the base name of the published JAR. It neither matches the gump id or the maven id.
  • The published JAR name has no version declaration e.g. many of the commons components do not declare a version as part of published JAR names.
  • The project id is not used as the base name of the published JAR and the published JAR name has no version declaration e.g. the worst case scenerio which is the Java Activation Framework JAR which doesn't even vaguely follow other Sun naming conventions and there is no version declaration in the published JAR name. There isn't even any version information in the manifest.

In most cases, any of these limitations can be overcome using the optional <jar> element or the JAR can be renamed. To date many of the Jakarta products have been renamed in the repository as it is likely in the near future that most Jakarta projects will choose to use Maven to build. But there isn't a firm policy about what to do in all cases which needs to be resolved.

Projects with multiple artifacts

Maven's dependency mechanism completely supports multiple project artifacts of any given type.

So here is what the entries look like for the ant 1.4.1 primary JAR and the optional JAR plus a bonus hypothetical:

So A), B) and C) are actually pointers to single artifacts in a group. So a single dependency is a reference to a single artifact in a group. Currently the type of an artifact defaults to a JAR if not specified. But a dependency might be a WAR file or a distribution. We tried to provide flexibility while providing a default for the type most used: The case where the artifact is a JAR required for building a project.

Remote Repository Layout

This document outlines the layout of Maven's remote repositories. Currently, the primary repository is house at here at Ibiblio, but you may create an use your own remote repositories provided they adhere to the structure outlined in this document.

Every separate project has its own directory in the repository where artifacts for that project can be stored. Each project has a unique project id and directory where a project stores its artifacts is named after the project id.

Within a project's directory various types of artifacts may be stored. Currently, the two most common types are JARs and distributions. Below is a little snapshot of what the remote repository looks like:

Local Repository Layout

There is a very minimally implemented set of interfaces that allow the structuring of the local repository in an arbitrary fashion. This has barely been fleshed and I am only using one class in the package directly at the moment. I still think the local and remote repositories should be structured the same, but in an attempt to make users happy I started a set of interfaces that will allow someone to layout their local side anyway they like and still interface with the remote repos in a consistent way. Though currently it is still required to have your local repository structured in the same way as the remote repository. I'm hoping that more user feedback will drive the completion of the interfaces or allow them to be dropped all together.

Site Generation

Maven can be used to generate an entire web site for your project. This web site will contain various reports generated by the numerous plugins included in Maven such as javadocs, metrics, unit test results, changelogs, and many more. The rest of this section talks about the various site customization options available in Maven.

Colors

By default, all Maven-generated sites use the same look and feel for consistency. This enables users to easily recognize a Maven-generated site and immediately feel comfortable searching for information on the site. Of course, the Maven development team understands that users might want to customize their own sites. The easiest method to alter the appearance of the Maven-generated site is to specify your own color scheme to use. This is as simple as setting the appropriate properties in your project's project.properties file. All of the available properties are described in the xdoc plugin.

Stylesheets

If you feel that colors are simply not enough to distinguish your site, you can specify your own stylesheet that will be used. To override the Maven-supplied stylesheet, copy your own and override the maven.css stylesheet in your ${basedir}/xdocs/stylesheets/ directory. You can also specify your own javadoc stylesheet by setting the maven.javadoc.stylesheet property.

Reports

Finally, if you want to customize which reports are automatically generated for your site, you need to include the reports tag in your project descriptor. As of this writing, if you do not utilize the reports tag, all of the plugin reports will be generated. This tag enables you to selectively choose which reports to include and exclude as well as the order of the reports.

The standard set of reports is currently hard coded into the xdoc plugin. These are

maven-changelog-plugin
maven-changes-plugin
maven-checkstyle-plugin
maven-developer-activity-plugin
maven-file-activity-plugin
maven-javadoc-plugin
maven-jdepend-plugin
maven-junit-report-plugin
maven-jxr-plugin
maven-license-plugin
maven-linkcheck-plugin
maven-pmd-plugin
maven-tasklist-plugin
      

If you wish to use the default reports but remove one or add one, the preferred method is to use a postGoal for xdoc:register-reports

Exclusion of All Maven-Generated Content

Users building documentation-only sites or sites that aggregate a lot of sub-projects might want to prevent the inclusion of the entire "Project Documentation" section of the navigation bar on their sites. This can be done by setting the maven.xdoc.includeProjectDocumentation property to the value of no. By default, Maven will include the "Project Documentation" section of the navigation bar which includes information about the project as well as links to the numerous Maven-generated reports.