About this Guide

The Maven User Guide is intended to help developers get acquainted with Maven by providing thorough descriptions and examples.

Thanks for choosing Maven!

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:

        <?xml version="1.0" encoding="ISO-8859-1"?>
        <project>

          <pomVersion>3</pomVersion>
          <id>maven</id>
          <name>Maven</name>
          <currentVersion>1.0-b5-dev</currentVersion>
          <organization>
            <name>Apache Software Foundation</name>
            <url>http://jakarta.apache.org/</url>
            <logo>/images/jakarta-logo-blue.gif</logo>
          </organization>
          <inceptionYear>2001</inceptionYear>
          <package>org.apache.${pom.id}</package>
          <logo>/images/${pom.id}.jpg</logo>

          <!-- Notice that shortDescription is defined after the description -->

          <description>${pom.shortDescription} that was created in ${pom.inceptionYear}.</description>
          <shortDescription>${pom.name} is a Java Project Management Tool</shortDescription>

        </project>

        

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:

        <?xml version="1.0" encoding="ISO-8859-1"?>
        <project>
          <extend>project.xml</extend>
  
          <id>super-extendo</id>
          <name>Super Extendo</name>

          <build>
            <unitTest>
              <includes>
                <include>**/*Test*.java</include>
              </includes>
              <excludes>
                <exclude>**/TestAll.java</exclude>
                <exclude>**/*Abstract*.java</exclude>
              </excludes>
            </unitTest>
          </build>
        </project>
        

Currently the resolution of the parent is fairly dumb and I haven't tested anything beyond a single level of extension. But even this level of extension coupled with interpolation can potentially buy you a lot. My motivation for this was an attempt at simplifying building for the commons.

You could define something like this for the master template:

        <project>
          <pomVersion>3</pomVersion>
          <id>commons-master</id>
          <name>Commons Master Maven POM</name>

          <organization>
            <name>Apache Software Foundation</name>
            <url>http://www.apache.org</url>
          </organization>

          <gumpRepositoryId>jakarta</gumpRepositoryId>

          <url>http://jakarta.apache.org/commons/${pom.id}.html</url>
          <issueTrackingUrl>http://nagoya.apache.org/</issueTrackingUrl>
          <siteAddress>jakarta.apache.org</siteAddress>
          <siteDirectory>/www/jakarta.apache.org/commons/${pom.id}/</siteDirectory>
          <distributionDirectory>/www/jakarta.apache.org/builds/jakarta-commons/${pom.id}/</distributionDirectory>

          <repository>
            <connection>scm:cvs:pserver:anoncvs@cvs.apache.org:/home/cvspublic:jakarta-commons/${pom.id}</connection>
            <url>http://cvs.apache.org/viewcvs/jakarta-commons/${pom.id}/</url>
          </repository>
          ...
        </project>

        

And for a child you could have something like this:

        <project>
          <id>commons-betwixt</id>
          <name>Betwixt</name>
          ...
        </project>
        

And what you will get is the child's ${pom.id} 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.

Properties Processing

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

  • ${maven.home}/bin/driver.properties
  • ${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.

How do Plug-in Properties Work?

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
  • ${maven.home}/bin/driver.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:

       maven.checkstyle.format = sun
       

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:

       maven.checkstyle.format = turbine
       

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.

Property Description Default Value
maven.mode.online true
maven.remote.repo.enabled true

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!

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.

Using Proxies

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.

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

## ----------------------------------------------------------
## ${user.home}/build.properties
## ----------------------------------------------------------
.
.
maven.proxy.host = my.proxyserver.com
maven.proxy.port = 8080
maven.proxy.username = username
maven.proxy.password = password
.
.

Naming Conventions

This document 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]:

        
        <project>
          <id>foo</id>
          ...
        </project>
        
        

All references from one project to another are to be made in terms of the unique project 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.

        
        <project>
          <id>foo</id>
          <name>The Grand Master Foo</name>
          ...
        </project>
        
        

All artifacts published by a project should be based on the project's unique identifier.

Depenendencies

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

        
        <project>
          <id>bar</id>
          <name>Baradelic Groove Machine</name>
          ...
          
          <dependencies>
          
            <dependency>
              <id>foo</id>
              <version>1.0</version>
            </dependency>
          
          </dependencies>
          
        </project>
        
        

So, the project bar which depends on version 1.0 of project foo. This dependency resolves to a JAR file that is stored in the local repository. The above entry assumes that the published JAR's name is based on the project id. 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 JAR artifacts

The dependency mechanism has been changed slightly in order to accommodate projects that produce/export multiple artifacts. This mechanism is a bit fugly but the Maven developers agreed we could use the format to be described below and later expand it to be more explicit and remain backward compatible.

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

        

        <dependencies>
  
          <!-- A -->
          <dependency>
            <id>ant</id>
            <version>1.4.1</version>
          </dependency>
  
          <!-- B -->
          <dependency>    
            <id>ant+optional</id>
            <version>1.4.1</version>
          </dependency>

          <!-- C -->
          <dependency>
            <id>ant:my-poor-name</id>
            <version>1.4.1</version>
          </dependency>

        </dependencies>

        
        

So A), B) and C) are actually pointers to single artifacts in a project. So a single dependency is a reference to a single artifact in a project. Everything right now defaults to JARs, but a dependency might be a JavaDoc index that is to be merged with other JavaDoc indexes to form a global index. Or a pointer to whatever, say a set of resources to pack up into a distribution. We tried to leave it open while preserving the most used case where the artifact is a JAR required for building something. Now for the fugly notation :-)

        

        A)
        project id = ant
        artifact name = ant-1.4.1.jar
        
        

If no "+" or "+" are present then it is assumed the artifact name is the same as the project id.

        

        B)
        project id = ant
        artifact name = ant-optional-1.4.1.jar
        
        

If a "+" is found then the artifact name is a concatenation of the lhs and rhs of the "+" where the "+" is replaced with a "-". If there are multiple JAR artifacts then hopefully they will be named consistently like foo-hubba-1.0.jar and foo-bubba-1.0.jar but of course we can count on this which brings us to C).

        
        C)
        project id = ant
        artifact name = my-poor-name.jar
        
        

This is hypothetical because ant does name their JARs in a consistent way but if a project exports a JAR artifact that has no relation to the project id then the ":" indicates to use the name on the rhs as is.

We need the project id in all cases because the new remote repository format stores all of a project's artifacts in a single directory which is named by the project id. So we have to account for artifacts where the base name is the project id, where the project id is used in the base name and where the artifact's base name has nothing to do with the project id.

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:

      
      repository
      |
      |-- ant
      |   |-- distributions
      |   `-- jars
      |       |-- ant-1.4.1.jar
      |       `-- ant-optional-1.4.1.jar
      +-- jsse
      |-- distributions
      `-- jars
          |-- jsse.jar
          |-- jcert.jar
          `-- jnet.jar
      
      

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.