Maven
Steven J Zeil
Abstract
Maven combines build management with configuration management (a future topic in this course). It attempts to standardize the build process in a way that improves consistency from project to project and enforces local best practices.
In this lesson, we will look at the capabilities and limitations of Maven and how projects can be structured to use it. We will look at how it works with some of our sample projects.
A major innovation offered by maven is its support for automatically importing third-party libraries for use by the project code. We’ll take a first look at this ability, though we will follow up in more detail later.
1 Why Maven?
Another Apache project, Maven came well after Ant had come to dominate the Java open source landscape.
-
Initially seen as a competitor or replacement for Ant
-
Maven addresses both
- build management (as does Ant)
- and configuration management (which Ant does not)
- Later, we’ll talk about Ivy, which adds configuration mgmt to Ant
1.1 Motivations for Maven
Grew out of an observation that many supposedly cooperative, related Apache projects had inconsistent and incompatible ant build structures.
Stated goals are
-
Making the build process easy
-
Providing a uniform build system
-
Providing quality project information
-
Providing guidelines for best practices development
-
Allowing transparent migration to new features
1.2 Getting Started with Maven
Perhaps the easiest way to illustrate maven is to follow the steps in Maven in 5 Minutes
-
Start with the command
mvn archetype:generate -DgroupId=edu.odu.cs \ -DartifactId=myProject \ -DarchetypeArtifactId=maven-archetype-quickstart \ -DinteractiveMode=false
- Lots of libraries (mainly comprising the latest version of Maven system itself) will be downloaded into your
\string~/.m2
directory. - A directory, myProject, will be created.
- Lots of libraries (mainly comprising the latest version of Maven system itself) will be downloaded into your
-
cd into the new directory and explore
- src directory structure
- pom.xml is the build file for this project
Building with the Sample Source
-
Run
mvn package
- Sample source code is compiled
- Sample unit test is run and executed.
- A jar file is created with the sample source code
-
Explore the target directory to see what has been placed there
-
For even more fun, try
mvn site
1.3 pom.xml
The Maven build file is pom.xml
. The POM for our simple project is
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>edu.odu.cs</groupId> ➀
<artifactId>codeAnnotation</artifactId> ➀
<packaging>jar</packaging> ➁
<version>1.0-SNAPSHOT</version>
<name>codeAnnotation</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
- Yep, more XML.
- ➀ Here you see the project identification we indicated.
- ➁ Set by the chosen archetypeArtifactId
2 Maven Innovations: archetypes
What you didn’t see in the pom.xml
were the targets/tasks that would be used.
- Like
ant
, Maven is based on task dependencies. - But the tasks are hidden in a remote file that describes the archetype
- The directory structures, targets, and tasks for building a particular kind of project.
- Individual projects cannot change the archetype
- Can _configure _ it by setting values of archetype-defined parameters.
- But cannot do things like add/remove tasks.
2.1 Archetypes Enforce Someone’s Idea of Best Practices
Archetypes can be supplied by
- the Maven project
- the community (have to search for them)
- company/project leaders
Creating Archetypes
Creating new archetypes is
- difficult
- is not supposed to be done on a project-by-project basis
2.2 Extending Maven for an Individual Project
Maven is usually extended by adding plugins
- Each plugin is a collection of related MOJOs, a Maven plain Old Java Object
- Each MOJO provides a specific function
- which can be bound to a specific goal of the life cycle for our selected project archetype
- Plugins cannot add/remove/reorder the task dependency tree of an archetype
- But they can add actions to be performed during some of those tasks.
2.2.1 Plugin Example - JFlex
This project adds a stage before compilation to generate some of the source code that then needs to be compiled.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>edu.odu.cs</groupId>
<artifactId>codeAnnotation</artifactId>
<packaging>jar</packaging>
<version>1.0</version>
<name>codeAnnotation</name>
<!-- site generation:
mvn test
mvn jxr:jxr surefire-report:report
mvn site
-->
<repositories>
<repository>
<snapshots>
<enabled>false</enabled>
</snapshots>
<id>forge350</id>
<name>ODU CS Forge350 Repository</name>
<url>http://forge350.cs.odu.edu/archiva/repositories/internal</url>
</repository>
</repositories>
<distributionManagement>
<repository>
<id>forge350Scp</id>
<name>ODU CS Forge350 Repository (scp)</name>
<url>scp://forge350.cs.odu.edu/var/lib/gforge/chroot/home/groups/mavenrepo1/htdocs/repo</url>
</repository>
</distributionManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<extensions>
<extension>
<groupId>org.apache.maven.wagon</groupId>
<artifactId>wagon-ssh</artifactId>
<version>2.2</version>
</extension>
</extensions>
<plugins>
<plugin>
<groupId>de.jflex</groupId>
<artifactId>maven-jflex-plugin</artifactId> ➀
<version>1.4.3</version>
<executions>
<execution>
<goals>
<goal>generate</goal> ➁
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.6</maven.compiler.source>
<maven.compiler.target>1.6</maven.compiler.target>
</properties>
</project>
The highlighted portions represent (most) of the changes required.
-
➀ Here we announce our intention to use a plugin that adds a
jflex
step to a java build. -
➁ Here we declare that
jflex
will be invoked during thegenerate
build step.
Using plugins is not always simple:
-
How do we know where to put our
jflex
input files?- We learn that by reading the documentation of the plugin.
-
How do we know that the proper time to use it is during the
generate
task?- We learn that by reading the documentation of the Java project archetype.
2.2.2 Plugin Example - Ant
One of the more popular ways to “escape” when Maven is getting in the way of a simple step is the antrun
plugin
-
For example, Maven’s built-in process for deciding what goes into a .jar file is to include the compiled classes and anything provided in src/main/resources
-
But what if I want to include some data files that were constructed during the build process?
- First, I need to run the programs to build those files.
- This definitely requires escaping from the normal life cycle
- Then I need to get them included into the Jar file
- The built-in mechanism for this is incredibly cumbersome
- First, I need to run the programs to build those files.
-
Easiest to handle both via a couple of embedded ant tasks
3 Maven Innovations: 3rd Party Libraries
3.1 Dependencies
Picking up with the example we used earlier.
-
Examine the pom.xml file and look for the
dependencies
section.You should see something like
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies>
-
This indicates that our project requires the junit package.
- But it’s an old version. JUnit changed a lot in version 4 (and even more in version 5).
3.1.1 Updating the Dependency
-
Change the version number to
<dependencies> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.10</version> <scope>test</scope> </dependencies>
- Could also say
[4.10,]
to get versions 4.10 or greater
- Could also say
-
Try
mvn package
again.
3.1.2 Fetching Dependencies
-
Maven does a transitive search over the dependencies for a project
- Tries to find a mutually compatible set of versions
- Helps if you give it some flexibility
- Tries to find a mutually compatible set of versions
-
Maven then downloads the required libraries automatically
- Downloaded libraries are cached (e.g.,
~/.m2
)
- Downloaded libraries are cached (e.g.,
3.1.3 Version Ranges
-
Version ranges can be specified as
[low,high]
[
and]
are inclusive. Use(
and)
for exclusive- If low or high are omitted, taken as \( \pm\infty \).
-
Examples
[4.0,4.10]
inclusive range[4.10,)
4.10 or anything more recent[4.10]
4.10 and nothing else4.10
with no brackets means “any version, but prefer 4.10”
3.1.4 Maven Repositories
-
By default, Maven searches the ibiblio repository, which can be human-searched here.
-
Try searching for junit
- Notice range of versions available
- Select one (e.g., 4.10)
- The “Maven” tab shows what to put into your
<dependencies>
section to request this version.
- Notice range of versions available
3.1.5 Transitive Dependencies
How does Maven know whether junit itself depends on other libraries?
-
Near the top of the junit 4.10 page, click to “View” the POM file:
Near the bottom, you will see
<dependencies> <groupId>org.hamcrest</groupId> <artifactId>hamcrest-core</artifactId> <version>1.3</version> <scope>compile</scope> </dependencies>
-
This is the same kind of info that we put into our own pom.xml file
- And is, presumably, taken from the pom.xml that the JUnit team used to maintain their builds.
- Publishing the dependency information along with the libraries leads to an accumulated base of information on library dependencies.
3.2 This was a Game Changer!
The combination of
- easy importation of libraries into a build, and
- large, well-known repositories of available libraries
was a tremendous advance.
Probably the major factor in attracting Java developers to start working with Maven.
3.2.1 “Imitation is the sincerest form of flattery”
(Oscar Wilde)
- Before long, Ant users were anxious for this same capability.
Ivy
is an Ant plugin that adds this to Ant- even searches the same Maven repositories for libraries
- Gradle would offer the same ability
- Other programming languages have sought to provide the same in the form of
- language-specific build managers
- language-specific repositories