Using Maven for builds

Maven is a widely-used tool for building Java projects.

For those familiar with the basics of Maven, here are some reminders regarding its use.

Running maven from the command line

After downloading Maven, you'll usually want to adjust your environment variables: The default Maven repository for downloaded jars and build artifacts has this default location:

${user.home}/.m2/repository

Common command lines

Examples: mvn dependency:analyze is a good sanity check. It detects 2 kinds of error: Some common options for commands: In general, a Maven command has this form:
mvn [options] [goal(s)] [phase(s)]

Archetype

An archetype is a canned template for a project structure, for example a jar or war. You typically start a new project by running a command like this to generate an 'archetypal' or standard directory structure:

A simple jar app:

>mvn archetype:generate -DartifactId=my-app -DgroupId=com.mycompany.app 
   -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
A web app:
>mvn archetype:generate -DartifactId=my-web-app -DgroupId=com.mycompany.app 
  -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false
For the web-app archetype, the tree looks like this after you have also run mvn install:
├───src
│ └───main
│ ├───resources
│ └───webapp
│ └───WEB-INF
└───target
 ├───classes
 ├───maven-archiver
 └───my-web-app
 ├───META-INF
 └───WEB-INF
 └───classes

Packaging: Lifecycle, Phase, and Goal

Packaging: 'LP(P:)G'
   1x Lifecycle
       Nx Phase
          Nx(plugin:)Goal
Packaging settings:

There are 3 lifecycles. Here they are, listed with their phases:

The phases in a lifecycle are ordered and cumulative: a later phase includes all earlier ones. For example, invoking mvn install will always cause all preceding phases in that lifecycle to be executed as well. Typical invocations of Maven specify 1..N phases. For example, mvn clean install invokes 2 phases from 2 independent lifecycles.

Each phase, in turn, has N plugin:goal's (much like an Ant target). Each goal is implemented by a plugin. You customize the behavior of a plugin by adding a <plugin> entry in the pom.xml.

Some important phases:

Resource-Filters

(Filter is actually a bad name; these refer to find-and-replace operations on special place-holder text in text files.)

In the resources directory, files can have place-holder references of the form ${blah}. Values for those references are defined in:

During the build, there is a maven phase (process-resources) which finds resource files and does a find-and-replace on all such ${blah} placeholder strings. In the pom.xml, you need to turn this mechanism on explicitly, like so:

<build>
 <resources>
  <resource>
   <directory>src/main/resources</directory>
   <filtering>true</filtering>
   </resource>
 </resources>
</build>

Maven coordinates

Maven uses the (rather silly) term of coordinates to refer to their conventional names for build artifacts: the who-what-when information.

Example: myorg.myproj:abc-web:1.1.0

The colon acts as a separator. The 3 basic items are, in order:

Maven defines conventional version strings that it's able to parse (examples above). The qualifier is simply plain text. The other items are numeric. Following this convention is highly recommended. A version of SNAPSHOT has specific meaning to Maven: the build is a development build, not a release build.

There are variations in the version string, having these items appearing before the version:

Layout

Maven projects have a conventional layout (a directory tree). A starter-version of that layout is generated when you start a project using a Maven archetype. The project layout can be altered, but in practice that's probably rarely done. When you deviate from the defaults, it requires more work to keep Maven functioning properly.

Names of tests

By default, in the test directory, Maven recognizes the following kinds of class names as unit tests: The idea is that it won't treat any other classes as tests. This let you place helper or utility classes beside your test classes.

Resource locations

Artifact names

You should avoid using dots in the artifactId, because it may lead to problems.

Version numbers

See above for details on version numbers. Note as well that in the pom.xml, a standard version number, appearing as just 3.2, acts as advice to Maven. Maven will try to use that version, as your preferred version, but it may, if needed, use a different version instead. You alter this behaviour, and hard-code to a precise version, by decorating the version with a special syntax, for example [3.2].

Versions have a special syntax:

Dependencies

If you declare a dependency on X, and X depends on Y, Maven will automagically fetch Y for you. A version is always needed. If it's not explicit, it's taken from somewhere: The scope of a dependency defines the contexts in which it's needed:

Jars not available in a remote Maven repository

In this case, you need to put the jar manually into the local repository, using a command similar to:
>mvn install:install-file -Dfile=non-maven-proj.jar 
 -DgroupId=some.group -DartifactId=non-maven-proj -Dversion=1 -Dpackaging=jar

Sharing POMs

There are 3 ways to share the content of a pom.xml:

Be aware of sloppy terms when reading docs about these ideas: the terms parent and child are used, but they should be avoided, because they mean different things according to who's talking. Your thinking will be clear if you stick to these terms instead:

Inheritance from super-pom (Project Inheritance): Aggregation: point to child-modules (Project Aggregation): It's legal to combine the above two styles: Be careful: whether or not something is inherited is tricky! You should verify the behaviour if there's any doubt.

The effective-pom:

Dependency vs Dependency Management

The difference between these 2 is with respect to poms that point to a super-pom. Let's say that your-pom points to a super-pom, via the usual parent tag.

Profiles

Some projects use profiles to customize the build for different environments. One of the main things to customize are database settings.

Example of the syntax:

<profile>
 <id>production</id>
 <properties>
   <db.driverClass>oracle.jdbc.driver.OracleDriver</db.driverClass>
   <db.connectionURL>jdbc:oracle:thin:@10.0.1.14:1521:APPS</db.connectionURL>
   <db.username>productionuser</db.username>
   <db.password>productionpassword</db.password>
 </properties>
</profile> 

Practices to consider