I've been using Maven 2 for a while now and I'm surprised that a lot of Java projects still use ant when they could be built using Maven 2. The difference between ant and Maven is that ant follows an imperative model --- take these files, run javac on them and then jar the output --- whereas Maven takes a declarative approach, essentially "here's a project, build it." As most Java projects are built pretty much the same way, it makes sense to get away from the drudgery of <javac> ant tasks and focus on actual programming.
Starting a project with Maven is pretty easy. Simply run the following command :
mvn archetype:create -DgroupId=im.jeanfrancois -DartifactId=helloWorld
This will create a new Maven project with a simple "Hello world!" application inside of it. If you open the project, you'll notice a file called pom.xml, which contains a simple project file. If you followed the previous instructions, you'll get a file similar to this.
<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>im.jeanfrancois</groupId>
<artifactId>helloWorld</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>helloWorld</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Note how the file contains no explicit calls to javac, filesets or nothing of the sort. All it mentions right now is a declaration that tells maven that this is a project that gets packaged as a jar file and depends on JUnit 3.8.1 for tests.
Three important attributes to note in the project file are the groupId, artifactId and version, which create an artifact identifier. The notion of an artifact is central to the Maven way of doing things and, as you can see, we refer to the dependency on junit by its groupId, artifactId and version.
Building the project is simply a matter of running mvn package which will fetch all dependencies for building --- JUnit in this case --- then run the unit tests and package the project into a jar file, placed in the "target" directory. Of course, if we were to run the jar file, we would get the following error:
java -jar helloWorld-1.0-SNAPSHOT.jar
Failed to load Main-Class manifest attribute from
helloWorld-1.0-SNAPSHOT.jar
While Maven has enough smarts to build a simple Java project out of the box, it doesn't know about the fact that we're building an executable jar instead of a library, so we'll need to tell it how to package the jar file. Add this section above the "dependencies" section:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>im.jeanfrancois.App</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
This tells Maven that, during the build cycle, the jar plugin needs to be configured to set the Main-Class attribute of the manifest to our application's entry point. Also, note the lack of a version number. If the version number is not specified on a plugin, Maven will use the latest version it can find, which is usually a good idea.
One of the areas where Maven shines is dependency management, where it will automatically fetch required dependencies and put them into the build. For example, let's add logging to our application. To do so, we'll need to get the commons-logging library, like so:
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging-api</artifactId>
<version>1.1</version>
</dependency>
We can then do something similar to LogFactory.getLog(App.class).debug("Entering main()"); on the first line of our main() method. We could also package our application as an executable jar with dependant jars attached, which is what I do for the iCalendar utilities, so you can refer to that POM file to see how it's done.
Another cool feature of Maven is the fact that IDE projects can be generated from the POM, thus allowing teams with multiple IDEs to work together. Providing the appropriate plugin is installed, one can then open Maven projects in IntelliJ IDEA, NetBeans or Eclipse. IDEA 7 can open Maven 2 projects out of the box, NetBeans requires the very well done MevenIDE2 plugin and as for Eclipse, try the m2eclipse plugin.
There are also numerous plugins for the Maven ecosystem, such as plugins to generate reports --- such as PMD, FindBugs or Cobertura --- or plugins to run various utilities on code for AOP instrumentation, C++ compilation, JNI binding generation and much more. Try Maven today!
Nice write-up. But all except the last point are valid for Ant as well. Not out of the box, but with custom scripts - which you'll create the second or third time you repeat to write similar things. Maven is nice for all the things it does, but you have less control, plugins maybe buggy, and after six month continuous use, you may be able to use most of its features - that is some expense for a tool, which should be invisible in an ideal world ...