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!
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.
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.
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.
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:
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.
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.
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.
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, <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.
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
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.
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
Inside of each goal, there are Jelly tags that you provide to perform functionality. Let's look at the code from our sample
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.
This executes the Ant task mkdir
, which simply creates a directory.
The directory is specified using a variable, ${maven.build.dir}
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.
var
attribute is the variable that will
be assigned the new list.
delim
attribute is the delimiter used to separate
items in the string
tokenize
tag in this case is a variable,
goals
, set a couple of lines previously, which contains
compile and test separated by commas
The forEach tag provides a simple loop facility. It executes it's body each time through the loop.
items
attribute is an expression that is evaluated to get the
the collection to be iterated through
var
attribute specifies the variable to place
each item in, as the collection is processed. The variable is available
to the forEach
body.
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.
The properties files in Maven are processed in the following order:
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-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:
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.
The following is a list of properties that change the way Maven works.
Property | Description | Default 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 |
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 |
If you only have access via a proxy then Maven obeys the following properties.
Proxy Properties | Description |
---|---|
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.
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:
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!
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.
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:
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.
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.
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.
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:
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:
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:
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.
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:
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:
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.
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.
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:
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.
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.
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.
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.
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
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.