Maven: The Complete Reference

3.2. The POM

Maven projects, dependencies, builds, artifacts: all of these are objects to be modeled and described. These objects are described by an XML file called a Project Object Model. The POM tells Maven what sort of project it is dealing with and how to modify default behavior to generate output from source. In the same way a Java web application has a web.xml that describes, configures, and customizes the application, a Maven project is defined by the presence of a pom.xml. It is a descriptive declaration of a project for Maven; it is the figurative “map” that Maven needs to understand what it is looking at when it builds your project.

You could also think of the pom.xml as analogous to a Makefile or an Ant build.xml. When you are using GNU make to build something like MySQL, you’ll usually have a file named Makefile that contains explicit instructions for building a binary from source. When you are using Apache Ant, you likely have a file named build.xml that contains explicit instructions for cleaning, compiling, packaging, and deploying an application. make, Ant, and Maven are similar in that they rely on the presence of a commonly named file such as Makefile, build.xml, or pom.xml, but that is where the similarities end. If you look at a Maven pom.xml, the majority of the POM is going to deal with descriptions: Where is the source code? Where are the resources? What is the packaging? If you look at an Ant build.xml file, you’ll see something entirely different. You’ll see explicit instructions for tasks such as compiling a set of Java classes. The Maven POM is declarative, and although you can certainly choose to include some procedural customizations via the Maven Ant plugin, for the most part you will not need to get into the gritty procedural details of your project’s build.

The POM is also not specific to building Java projects. While most of the examples in this book are geared towards Java applications, there is nothing Java-specific in the definition of a Maven Project Object Model. While Maven’s default plugins are targeted at building JAR artifacts from a set of source, tests, and resources, there is nothing preventing you from defining a POM for a project that contains C# sources and produces some proprietary Microsoft binary using Microsoft tools. Similarly, there is nothing stopping you from defining a POM for a technical book. In fact, the source for this book and this book’s examples is captured in a multi-module Maven project which uses one of the many Maven Docbook plugins to apply the standard Docbook XSL to a series of chapter XML files. Others have created Maven plugins to build Adobe Flex code into SWCs and SWFs, and yet others have used Maven to build projects written in C.

We’ve established that the POM describes and declares, it is unlike Ant or Make in that it doesn’t provide explicit instructions, and we’ve noted that POM concepts are not specific to Java. Diving into more specifics, take a look at Figure 3.1, “The Project Object Model” for a survey of the contents of a POM.

figs/web/pom-relationships_pom-small.png

Figure 3.1. The Project Object Model


The POM contains four categories of description and configuration:

General project information
This includes a project’s name, the URL for a project, the sponsoring organization, and a list of developers and contributors along with the license for a project.
Build settings
In this section, we customize the behavior of the default Maven build. We can change the location of source and tests, we can add new plugins, we can attach plugin goals to the lifecycle, and we can customize the site generation parameters.
Build environment
The build environment consists of profiles that can be activated for use in different environments. For example, during development you may want to deploy to a development server, whereas in production you want to deploy to a production server. The build environment customizes the build settings for specific environments and is often supplemented by a custom settings.xml in ~/.m2. This settings file is discussed in Chapter 5, Build Profiles and in the section Section 15.2, “Settings Details”.
POM relationships
A project rarely stands alone; it depends on other projects, inherits POM settings from parent projects, defines its own coordinates, and may include submodules.

3.2.1. The Super POM

Before we dive into some examples of POMs, let’s take a quick look at the Super POM. All Maven project POMs extend the Super POM, which defines a set of defaults shared by all projects. This Super POM is a part of the Maven installation. Depending on the Maven version it can be found in the maven-x.y.z-uber.jar or maven-model-builder-xy.z.jar file in ${M2_HOME}/lib. If you look in this JAR file, you will find a file named pom-4.0.0.xml under the org.apache.maven.model package. It is also published on the Maven reference site that is available for each version of Maven separately and e.g. for Maven 3.1.1 it can be found with the Maven Model Builder documentation. A Super POM for Maven is shown in The Super POM.

Tip

An analogy to how the Super POM is the parent for all Maven POM files, would be how java.lang.Object is the top of the class hierarchy for all Java classes.

The Super POM. 

<project>
    <modelVersion>4.0.0</modelVersion>
    <name>Maven Default Project</name>

    <repositories>
        <repository>
            <id>central</id> (1)
                <name>Maven Repository Switchboard</name>
                <layout>default</layout>
                <url>http://repo1.maven.org/maven2</url>
                <snapshots>
                    <enabled>false</enabled>
                </snapshots>
        </repository>
    </repositories>

    <pluginRepositories>
        <pluginRepository>
            <id>central</id> (2)
                <name>Maven Plugin Repository</name>
                <url>http://repo1.maven.org/maven2</url>
                <layout>default</layout>
                <snapshots>
                    <enabled>false</enabled>
                </snapshots>
                <releases>
                    <updatePolicy>never</updatePolicy>
                </releases>
        </pluginRepository>
    </pluginRepositories>

    <build> (3)
            <directory>${project.basedir}/target</directory>
            <outputDirectory>
                ${project.build.directory}/classes
            </outputDirectory>
            <finalName>${project.artifactId}-${project.version}</finalName>
            <testOutputDirectory>
                ${project.build.directory}/test-classes
            </testOutputDirectory>
            <sourceDirectory>
                ${project.basedir}/src/main/java
            </sourceDirectory>
            <scriptSourceDirectory>src/main/scripts</scriptSourceDirectory>
            <testSourceDirectory>
                ${project.basedir}/src/test/java
            </testSourceDirectory>
            <resources>
                <resource>
                    <directory>${project.basedir}/src/main/resources</directory>
                </resource>
            </resources>
            <testResources>
                <testResource>
                    <directory>${project.basedir}/src/test/resources</directory>
                </testResource>
            </testResources>


            <pluginManagement> (4)
                    <plugins>
                        <plugin>
                            <artifactId>maven-antrun-plugin</artifactId>
                            <version>1.3</version>
                        </plugin>
                        <plugin>
                            <artifactId>maven-assembly-plugin</artifactId>
                            <version>2.2-beta-2</version>
                        </plugin>
                        <plugin>
                            <artifactId>maven-clean-plugin</artifactId>
                            <version>2.2</version>
                        </plugin>
                        <plugin>
                            <artifactId>maven-compiler-plugin</artifactId>
                            <version>2.0.2</version>
                        </plugin>
                        <plugin>
                            <artifactId>maven-dependency-plugin</artifactId>
                            <version>2.0</version>
                        </plugin>
                        <plugin>
                            <artifactId>maven-deploy-plugin</artifactId>
                            <version>2.4</version>
                        </plugin>
                        <plugin>
                            <artifactId>maven-ear-plugin</artifactId>
                            <version>2.3.1</version>
                        </plugin>
                        <plugin>
                            <artifactId>maven-ejb-plugin</artifactId>
                            <version>2.1</version>
                        </plugin>
                        <plugin>
                            <artifactId>maven-install-plugin</artifactId>
                            <version>2.2</version>
                        </plugin>
                        <plugin>
                            <artifactId>maven-jar-plugin</artifactId>
                            <version>2.2</version>
                        </plugin>
                        <plugin>
                            <artifactId>maven-javadoc-plugin</artifactId>
                            <version>2.5</version>
                        </plugin>
                        <plugin>
                            <artifactId>maven-plugin-plugin</artifactId>
                            <version>2.4.3</version>
                        </plugin>
                        <plugin>
                            <artifactId>maven-rar-plugin</artifactId>
                            <version>2.2</version>
                        </plugin>
                        <plugin>
                            <artifactId>maven-release-plugin</artifactId>
                            <version>2.0-beta-8</version>
                        </plugin>
                        <plugin>
                            <artifactId>maven-resources-plugin</artifactId>
                            <version>2.3</version>
                        </plugin>
                        <plugin>
                            <artifactId>maven-site-plugin</artifactId>
                            <version>2.0-beta-7</version>
                        </plugin>
                        <plugin>
                            <artifactId>maven-source-plugin</artifactId>
                            <version>2.0.4</version>
                        </plugin>
                        <plugin>
                            <artifactId>maven-surefire-plugin</artifactId>
                            <version>2.4.3</version>
                        </plugin>
                        <plugin>
                            <artifactId>maven-war-plugin</artifactId>
                            <version>2.1-alpha-2</version>
                        </plugin>
                    </plugins>
            </pluginManagement>

            <reporting>
                <outputDirectory>target/site</outputDirectory>
            </reporting>
</project>

The Super POM defines some standard configuration variables that are inherited by all projects. Those values are captured in the annotated sections:

(1)

The default Super POM defines a single remote Maven repository with an ID of central. This is the Central Repository that all Maven clients are configured to read from by default. This setting can be overridden by a custom settings.xml file. Note that the default Super POM has disabled snapshot artifacts on the Central Repository. If you need to use a snapshot repository, you will need to customize repository settings in your pom.xml or in your settings.xml. Settings and profiles are covered in Chapter 5, Build Profiles and in Section 15.2, “Settings Details”.

(2)

The Central Repository also contains Maven plugins. The default plugin repository is the central Maven repository. Snapshots are disabled, and the update policy is set to “never,” which means that Maven will never automatically update a plugin if a new version is released.

(3)

The build element sets the default values for directories in the Maven Standard Directory layout.

(4)

Starting in Maven 2.0.9, default versions of core plugins have been provided in the Super POM. This was done to provide some stability for users that are not specifying versions in their POMs. In newer versions some of this has been migrated out of the file. However you can still see the versions that will be used in your project using mvn help:effective-pom.

figs/web/pom-relationships_pom-inherit-simple-super.png

Figure 3.2. The Super POM is always the base Parent


3.2.2. The Simplest POM

All Maven POMs inherit defaults from the Super POM (introduced earlier in the section Section 3.2.1, “The Super POM”). If you are just writing a simple project that produces a JAR from some source in src/main/java, want to run your JUnit tests in src/test/java, and want to build a project site using mvn site, you don’t have to customize anything. All you would need, in this case, is the simplest possible POM shown in The Simplest POM. This POM defines a groupId, artifactId, and version: the three required coordinates for every project.

The Simplest POM. 

<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.sonatype.mavenbook.ch08</groupId>
    <artifactId>simplest-project</artifactId>
    <version>1</version>
</project>

Such a simple POM would be more than adequate for a simple project—e.g., a Java library that produces a JAR file. It isn’t related to any other projects, it has no dependencies, and it lacks basic information such as a name and a URL. If you were to create this file and then create the subdirectory src/main/java with some source code, running mvn package would produce a JAR in target/simple-project-1.jar.

3.2.3. The Effective POM

$ mvn help:effective-pom

Executing the effective-pom goal should print out an XML document capturing the merge between the Super POM and the POM from The Simplest POM.

3.2.4. Real POMs

Maven is something of a chameleon; you can pick and choose the features you want to take advantage of. Some open source projects may value the ability to list developers and contributors, generate clean project documentation, and manage releases automatically using the Maven Release plugin. On the other hand, someone working in a corporate environment on a small team might not be interested in the distribution management capabilities of Maven nor the ability to list developers. The remainder of this chapter is going to discuss features of the POM in isolation. Instead of bombarding you with a 10-page listing of a set of related POMs, we’re going to focus on creating a good reference for specific sections of the POM. In this chapter, we discuss relationships between POMs, but we don’t illustrate such a project here.