Managing Builds with 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.
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
Maven as a Build Manager
Maven uses an underlying task dependency model, but the tasks and their dependencies are pre-defined for a collection of archetype projects.
As a consequence, maven offers far less flexibility than ant, but a basic, unaltered maven build may include tasks that less experienced developers would never think to include or might have difficulty adding to a more conventional build manager.
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
Uniform Build System
-
Maven supports archetype projects that standardize
-
directory structure
- Source code kept in separate directory tree from both intermediate and final build products
- Tests occupy separate subtrees of the source and product trees
-
“Life Cycle”
- Really, a presumptuous name on their part for a build process
- A sequence of goals
-
-
Archetypes can be obtained from the Maven project or tailored for an organization.
Providing quality project information
-
Provides easy access to report tools
-
Aids in building & maintaining project web sites (e.g.)
Providing guidelines for best practices development
-
Directory structures (already discussed)
-
Unit testing
-
Encourage familiarity with approved archetypes
2 Maven as a Build Manager
Perhaps the best way to illustrate this is to follow the steps in Maven in 5 Minutes
-
Start with the command
mvn archetype:generate -DgroupId=edu.odu.cs \ -DartifactId=codeAnnotation \ -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, codeAnnotation, 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
OK, that was fun…
Let’s try this with some real source code.
-
Delete the target directory (or run
mvn clean
) -
Replace the contents of src/main/java and src/test/java by the corresponding contents from my code Annotation project.
- Also, copy src/main/jflex while we’re at it, though we won’t use this right away.
-
Try
mvn package
again.
What Went Wrong?
-
A glance at the code with the error messages won’t show anything obvious.
- But I happen to know that Maven defaults to running the Java compiler in Java 5 compatibility mode
- This code uses Java 7 features
-
Edit the pom.xml file and, just above the
<dependencies>
section, add<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.7</maven.compiler.source> <maven.compiler.target>1.7</maven.compiler.target> </properties>
-
Then try
mvn package
again
That was a little better
-
The main source code compiled successfully.
-
The error was in the compilation of the unit tests
- The first error message says
[ERROR] /home/.../codeAnnotation/src/test/java/edu/odu/cs/codeAnnotation/TestC2HOptions.java:[3,23] package org.junit does not exist
- The first error message says
-
Looks to be a problem with the JUnit library
-
In the original project, I was keeping a copy of junit4.jar in the project directory.
-
A clumsy solution
-
Which we’ll solve when we take up configuration management.
-
3 Case Studies
3.1 Simple Java Build
Well, we pretty much just did that.
-
Use
mvn archetype:generate
to set up the directories and build file. -
Replace maven’s “Hello World” code by the real source code.
3.2 Java Build with Code Generation
Not All Sourcecode is Hand-Written
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>
<url>https://secweb.cs.odu.edu/~zeil/cs795SD/s13/Directory/topics.html</url>
<description>
This is a tool used to parse code listings and to
generate syntax-highlighted C++/Java listings in both
HTML and LaTeX.
Markup can be added in the form of special comments that will
be recognized as instructions to highlight blocks of code, to
add callout symbols, or to insert vertical ellipses.
</description>
<!-- site generation:
mvn test
mvn surefire-report:report
mvn site
-->
<repositories>
</repositories>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>de.jflex</groupId>
<artifactId>jflex</artifactId>
<version>1.4.3</version>
</dependency>
</dependencies>
<build>
<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>
</pluginManagement>
</build>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
</project>
TYhe 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.
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.
3.3 C++ Multi-project Build
Not even going to try and go there.
I’ve never had much luck getting maven to work with C++.