Last modified: Nov 20, 2013
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
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
Picking up with the example we used earlier.
Edit 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>
Change the version number to
<dependencies>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependencies>
Try mvn package again.
By default, Maven searches the ibiblio repository, which can be human-searched here.
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>
A basic shared repository can be found here.
To add access to it, we add this to our pom.xml:
<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>
Publishing to a Repository
Suppose that we want to publish our jar to a repository.
<repositories>
⋮
</repository>
</repositories>
<distributionManagement>
<repository>
<id>forge350-publish</id>
<name>ODU CS Forge350 Repository</name>
<url>http://forge350.cs.odu.edu/archiva/repository/internal/</url>
</repository>
</distributionManagement>
Connection Info
In addition to adding the output repository to the POM, you need to provide your authentication info for the servers that you use in \string/.m2/settings.xml:
<settings>
<servers>
<server>
<id>forge350-publish</id> /**co1*/
<username>yourLogin</username>
<password>yourPassword</password> /**co2*/
<!-- privateKey>/path/to/your/private/key</privateKey --> /**co3*/
<filePermissions>664</filePermissions>
<directoryPermissions>775</directoryPermissions>
<configuration>
</configuration>
</server>
</servers>
</settings>
➊ This ID provides a handle for the distributionManagement tag in your POM to use identifying where you want to publish to.
➌ Probably a better idea is to use public/private key access.
Circling the Wagons
However, for whatever reason, communication with repositories has a separate extension mechanism, called wagons.
</dependencies>
<build>
<extensions>
<extension>
<groupId>org.apache.maven.wagon</groupId>
<artifactId>wagon-ssh</artifactId>
<version>2.2</version>
</extension>
</extensions>
</build>
If all is well…
Modification via Plugin
Much of the source code in this project is generated by jflex
Currently, we have replied on that generated code already being in our src/main/java
Maven has a jflex plugin that will convert jflex inputs in src/main/jflex to Java source code in the target directory and will include that generated code in the normal compilation.
Adding the JFlex Plugin
Modify the POM:
<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>
Maven Report Generation
Generating a Website
mvn site will generate a project website.
Most of the content will be highly generic, however.
The missing details have to be added to the POM
<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 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>
<issueManagement>
<system>Bugzilla</system>
<url>https://www.cs.odu.edu/~zeil/bugzilla/</url>
</issueManagement>
<ciManagement>
<system>Continuum</system>
<url>http://www.cs.odu.edu/~zeil/continuum</url>
<notifiers>
<notifier>
<type>mail</type>
<address>zeil@cs.odu.edu</address>
</notifier>
</notifiers>
</ciManagement>
<developers>
<developer>
<id>szeil</id>
<name>Steven Zeil</name>
<email>zeil@cs.odu.edu</email>
<roles>
<role>Project Manager</role>
<role>Programmer</role>
</roles>
<organization>ODU CS</organization>
</developer>
</developers>
<scm>
<connection>scm:svn:svn://scm.forge350.cs.odu.edu/var/lib/gforge/chroot/scmrepos/svn/jsheetsvn/trunk</connection>
<developerConnection>scm:svn:svn+ssh://sjzeil@scm.forge350.cs.odu.edu/var/lib/gforge/chroot/scmrepos/svn/jsheetsvn/trunk</developerConnection>
<url>https://forge350.cs.odu.edu/scm/?group_id=97</url>
</scm>
<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>
Adding Reports
<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 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>
<issueManagement>
<system>Bugzilla</system>
<url>https://www.cs.odu.edu/~zeil/bugzilla/</url>
</issueManagement>
<ciManagement>
<system>Continuum</system>
<url>http://www.cs.odu.edu/~zeil/continuum</url>
<notifiers>
<notifier>
<type>mail</type>
<address>zeil@cs.odu.edu</address>
</notifier>
</notifiers>
</ciManagement>
<developers>
<developer>
<id>szeil</id>
<name>Steven Zeil</name>
<email>zeil@cs.odu.edu</email>
<roles>
<role>Project Manager</role>
<role>Programmer</role>
</roles>
<organization>ODU CS</organization>
</developer>
</developers>
<scm>
<connection>scm:svn:svn://scm.forge350.cs.odu.edu/var/lib/gforge/chroot/scmrepos/svn/jsheetsvn/trunk</connection>
<developerConnection>scm:svn:svn+ssh://sjzeil@scm.forge350.cs.odu.edu/var/lib/gforge/chroot/scmrepos/svn/jsheetsvn/trunk</developerConnection>
<url>https://forge350.cs.odu.edu/scm/?group_id=97</url>
</scm>
<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>
<plugin> /**co1*/
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
</plugin>
<!--
<plugin> /**co2*/
<groupId>com.atlassian.maven.plugins</groupId>
<artifactId>maven-clover2-plugin</artifactId>
<version>2.4</version>
</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>
<reporting> /**co3*/
<plugins>
<plugin>
<artifactId>maven-javadoc-plugin</artifactId> /**co4*/
<version>2.9</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jxr-plugin</artifactId> /**co5*/
<version>2.3</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-report-plugin</artifactId> /**co6*/
<version>2.13</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId> /**co7*/
<configuration>
<targetjdk>1.6</targetjdk>
<rulesets>
<ruleset>rulesets/java/basic.xml</ruleset>
<ruleset>rulesets/java/braces.xml</ruleset>
<ruleset>rulesets/java/clone.xml</ruleset>
<ruleset>rulesets/java/codesize.xml</ruleset>
<ruleset>rulesets/java/comments.xml</ruleset>
<ruleset>rulesets/java/controversial.xml</ruleset>
<ruleset>rulesets/java/coupling.xml</ruleset>
<ruleset>rulesets/java/design.xml</ruleset>
<ruleset>rulesets/java/empty.xml</ruleset>
<ruleset>rulesets/java/finalizers.xml</ruleset>
<ruleset>rulesets/java/imports.xml</ruleset>
<ruleset>rulesets/java/naming.xml</ruleset>
<ruleset>rulesets/java/strictexception.xml</ruleset>
<ruleset>rulesets/java/strings.xml</ruleset>
<ruleset>rulesets/java/typeresolution.xml</ruleset>
<ruleset>rulesets/java/unusedcode.xml</ruleset>
</rulesets>
<format>xml</format>
<linkXref>true</linkXref>
<sourceEncoding>utf-8</sourceEncoding>
<minimumTokens>100</minimumTokens>
</configuration>
</plugin>
<!--
<plugin>
<artifactId>maven-clover-plugin</artifactId> /**co8*/
</plugin>
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId> /**co9*/
<version>2.6</version>
</plugin>
</plugins>
</reporting>
</project>
Maven is wonderful when your project matches the archetype.
When it doesn’t …
<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>
Maven plugin documentation is often atrocious
Sometimes Doing the Easiest Things
… will be the hardest thing to accomplish in Maven
Basically, Maven is wonderful when your projects matches an archetype, and tortuous when it does not.
Maven and 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
Easiest to handle both via a couple of embedded ant tasks
Maven and Eclipse
Integrating Maven into eclipse is more than just allowing you run mvn as the build command