Better Version Enforcement In Maven

This post is inspired by episode 341 of the Java Posse.

One criticism of Maven (esp. when compared to Apache Ivy) is a lack of enforcement of hard version numbers in dependencies. Maven allows you to specify inclusive and exclusive ranges for dependencies. The problem is, by default Maven doesn’t enforce those ranges.

Here’s an example of two modules. The first has a hard dependency of JUnit 3.8.1 while the second explicitly wants 4.0.

<project>
	<modelVersion>4.0.0</modelVersion>
	<groupId>name.joshpeters.example</groupId>
	<artifactId>Module1</artifactId>
	<version>1.0.0-SNAPSHOT</version>
	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>[3.8.1]</version>
		</dependency>
	</dependencies>
</project>
<project>
	<modelVersion>4.0.0</modelVersion>
	<groupId>name.joshpeters.example</groupId>
	<artifactId>Module2</artifactId>
	<version>1.0.0-SNAPSHOT</version>
	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>[4.0]</version>
		</dependency>
	</dependencies>
</project>

Now a good practice would be to prevent builds from succeeding if there are incompatibilities with the dependencies. If Module1 fails to execute using JUnit 4, it’d be nice to know as soon as possible. (Another criticism of Maven is that it tends to obfuscate any errors encountered.)

Fortunately, as with most things Maven, the solution lies in the use of plugins. In this case, we can configure the Maven Dependency Plugin to run its analyze-only goal during resource processing. Doing so will trigger a failure anytime we have such version issues in our dependencies at a time in our build where we get more value (IMO) out of failing.

Normally, the verify phase would be where the dependency plugin would execute, which may not be executed at all if you just execute mvn package! We don’t want such a false positive if we can avoid it, so here’s a configuration that gets us what the more Ivy-style failure:

<project … >
…
	<dependencies>
		<dependency>
			<groupId>name.joshpeters.example</groupId>
			<artifactId>Module2</artifactId>
			<version>1.0.0-SNAPSHOT</version>
		</dependency>
		<dependency>
			<groupId>name.joshpeters.example</groupId>
			<artifactId>Module1</artifactId>
			<version>1.0.0-SNAPSHOT</version>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-dependency-plugin</artifactId>
				<version>2.2</version>
				<executions>
					<execution>
						<id>analyze</id>
						<goals>
							<goal>analyze-only</goal>
						</goals>
						<phase>process-resources</phase>
						<configuration>
							<failOnWarning>true</failOnWarning>
						</configuration>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
…
</project … >

failOnWarning set to true will cause analyze-only to fail whenever there are dependency compatibility issues.

Here’s what Maven 3 now reports back early in its lifecycle:

[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.615s
[INFO] Finished at: Wed Apr 06 21:06:35 CDT 2011
[INFO] Final Memory: 5M/268M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-dependency-plugin:2.2:analyze-only (analyze) on project PROJECT: Dependency problems found -> [Help 1]
This entry was posted in java, maven and tagged , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Spam Protection by WP-SpamFree