Maven, a first day guide

This is the first chapter of a mini-guide that will try first to set clear what the purpose of Apache Maven is, and then show you how you can use it in your Java projects.

I have always preferred to start learning by example and by doing things instead of by reading lengthy manuals (there will be time for that once I have started to get the feel of the technology). So, I will write this aimed to a learner like me, hoping that some of you also prefer learning it this way.

Anyways, the introduction is over, let’s get to the meat :-)

Maven

There are plenty of sites telling you what Maven is, so I will tell you what you will usually use Maven for. When developing a Java project, you will use Maven to perform tasks such as building, packaging, deploying or testing your project. Then, why use it instead of any other tool? These are some of Maven strong points:

  • All information regarding how you want to perform all these tasks is centralized in a single file: pom.xml.
  • Convention over configuration. If you adhere to Maven’s conventions (for example, where to place your .java files), your pom.xml file will be very concise.
  • A nice plugin ecosystem. Maven will probably have a plugin that does that not so usual task you want to perform.
  • And finally, dependency control. One of its more known features, with Maven it’s very easy to configure and check what Jars you need for each stage (building, testing and running).

In case you have used Ant to build-test-deploy-etc. your project, Maven can probably be its substitute, provided that you find Maven’s way of doing the task more adequate.

Installation

If you haven’t already, you may get Maven from here: http://maven.apache.org/download.html. There is also installation instructions for Windows and Unix-like systems.

A note to Linux users, even though you can probably get Maven from your distro’s packaging system, you may consider installing it standalone. At least in Debian/Ubuntu systems the package pulls a gazillion dependencies that you don’t need.

The minimal pom.xml

OK, you have Maven installed, let’s see what it can do for you. Create a directory, and place this pom.xml file in it:

<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">
 
  <!-- Maven's POM version -->
  <modelVersion>4.0.0</modelVersion>
 
  <!-- When packaging, a JAR file will be produced -->
  <packaging>jar</packaging>
 
  <!-- And the file will be named my-jar.jar -->
  <artifactId>my-jar</artifactId>
 
  <!-- This tells Maven how your jar should be archived, should you
     want to use it as a dependency for another project -->
  <groupId>tld.testing</groupId>
  <version>0.1-Alpha</version>
 
  <!-- The projects name -->
  <name>My Project</name>
 
</project>

It basically tells Maven that it should create a JAR file. You may now execute mvn package in the directory and you will see Maven create the requested JAR file in the also created target directory. Of course, the JAR will be empty apart from an auto-generated Manifest as there are no Java source files yet.

Take care, if it’s the first time you execute a Maven’s stage, it will download the internet (everything will be saved locally, so next time you execute it, probably nothing will have to be downloaded).

Adding files to compile

If you have read Maven’s output to the last command, it will have told you that it had no files to compile. So, lets add a simple Java file, called App.java.

package mypkg;
 
public class App {
 
  public static void main(String[] args) {
    System.out.println("Hello Maven!");
  }
 
}

You will have to create the directory src/main/java/mypkg and place it in there. Once it’s done, type again mvn package in the root of your project. You can check the target directory and see your compiled class in there under the classes directory, and the updated Jar file with the App.class now inside.

As a final check of this stage, execute mvn exec:java -Dexec.mainClass="mypkg.App". This tells Maven to execute your compiled class, so you will see if everything is OK (you should see the “Hello Maven!” output between Maven’s info messages).

As you have seen, by adhering to Maven’s convention of where the source files should be placed, no extra configuration has been needed in the pom.xml file.

Testing stage and the first dependency

If you read Maven’s output when packaging, you may have noticed a “No tests to run” output between the compiling and packaging step. In Maven’s way of doing things, there is a test stage between compiling and packaging. That means, once it has compiled your project, Maven will run any unit tests that you have against the compiled files, and in case it succeeds, it will procede to package. That’s a good thing in my book, so let’s give Maven a test to run.

Suppose we want to run a simple unit test coded in JUnit. We will need the JUnit JAR in the classpath, but only during the test stage. It’s now time to start using Maven’s dependency control, so we add the following before the </project> closing tag in the pom.

  <dependencies>
    <dependency>
      <!-- Group and artifact id tell Maven where to look 
        for a dependency -->
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <!-- And the version completes the information so it 
        knows exactly what JAR it must download -->
      <version>3.8.1</version>
      <!-- We want JUnit only in the test stage -->
      <scope>test</scope>
    </dependency>
  </dependencies>

With that information, next time you package your project Maven will automatically download JUnit JAR and add it in the classpath during your tests.

So let’s see if that works. Create a very simple (and not useful at all) JUnit test in a file called AppTest.java:

import junit.framework.TestCase;
 
public class AppTest extends TestCase {
 
  public void testSum() throws Exception {
    assertEquals(2, 1+1);
  }
 
}

And place that file in src/test/java/mypkg. Then, execute mvn package again. You will see how Maven performs the test, outputs the report of the test stage and proceeds to package as there were no test failures.

With a minimal pom.xml, you have configured Maven to compile, test and package your project. That pom.xml file and directory structure would be a good starting point template, but Maven has a better solution than the copy pasting of that structure…

The quickstart archetype

With Maven you can use lots of predefined archetypes that act like templates when starting a Maven managed project. This is very handy for when you are starting a WAR project or have some configuration that requires a predetermined configuration in the pom and file structure.

Open a terminal in a directory other than the one in which you did your first project, and:

  1. Execute: mvn archetype:generate
  2. Select maven-archetype-quickstart, it’s 15 on my list.
  3. Define value for groupId: : tld.testing
  4. Define value for artifactId: : my-jar
  5. Define value for version: 1.0-SNAPSHOT: : 0.1-Alpha
  6. Define value for package: tld.testing: : mypkg

Once you finish, Maven will create a my-jar directory in which you will have an equivalent pom and directory structure to the one you hand-made in the previous sections. The good thing is now you know why it defines those things, and have a better understanding of Maven than if you had just used the archetype.

Finishing the day

Well, enough Maven for a day I would say. It came out more verbose than I initially wanted, but without the intro it felt a little lacking. I promise next chapters will be more to the point with more examples and less talking!