The Problem: Confusion
I've had a lot of small
discussions recently with people where they were just absolutely not
interested in using Maven. Has it somehow gotten a bad reputation when
I wasn't looking? Am I missing something? When did I suddenly become
the guy using a tool that was too slow, or not agile enough for
everybody? I can still sing and dance and jump like you guys, too!
Even if I do use Maven...
So, let old Josh tell you a little
bit about Maven. Maybe we're not all talking about the same thing.
Consider this a survival guide to Maven.
Maven, like this
guide, assumes you're trying to solve the 80% cases effectively.
Already, we have a point of confusion!
I'm pretty confident
that your first thoughts on that last sentence were to what Maven
considers "80%," and you're probably wondering what you might
reasonably call Ant's "80%" cases. I would argue that Maven's "80%"
is 80% of a much, much bigger pie.
I haven't met an Ant build
yet that couldn't be cut down in complexity by using Maven. Sure,
sometimes the resulting Maven pom.xml was more verbose
(though, that doesn't happen all that often in practice, either), but
that's not the same as complexity. Intrinsic complexity is one thing.
Surface complexity is another. I define intrinsic complexity as the
concepts required to effectively deal with a problem in a problem
space. I define apparent complexity as the busy work a process
presents you with to obtain a goal.
I'm pretty convinced Ant
suffers from both of those kinds of complexities. I wasn't going to
start any bar fights about it, but I was pretty sure. Then, Ruby On
Rails debuted and made code generation popular again. It brought
"convention over configuration" to the mainstream. Then, I knew I was
on to something with Maven.
I might argue that when you
download Ant and decide to keep it in your tool chain, you think of it
as providing a solution, assuming you've configured it, to:
- compiling Java source files into classes
-
copying resources to the right place, such as .XML files, .properties
files, etc.
- generating .jar or .war artifacts from the
aforementioned classes.
- generating JavaDocs. I'm adding this
one as a "maybe." Does anybody still do this and actually keep
JavaDocs floating around? Is the Eclipse or IntelliJ support for
rendering in-popup the contents of the JavaDoc not enough?
The enlightened Ant user will also, maybe, add dependency
management with Ivy to Ant's 80% cases. I mention this to be fair,
though I highly doubt it's that common. I suspect that a lot of Ant
users would still relegate that to the fringe 20% cases.
Alright, so we have our 80%. Most people have a sample ant build.xml
that they've lugged around and, when it's time to seed a new project,
they plop it into place and it's got some variables that need to be
replaced and then it does most of the things above. Except JavaDocs
and Ivy. I'd be surprised, anyway.
Maven's got all of those
features - right out of the box - in 5 lines of XML and a standard
directory structure. This is where it stops being a fair fight.
No matter how much you tug or pull against that list above, chances
are you're at least going to use Ant to compile. No way around
it. Even the simplest Ant configuration requires more exertion to
acheive that than Maven does. This point, and this point alone, is why
I'm just not convinced people are taking a look at this and
understanding it. If the goal is simplicity, then there's nothing
simpler than nothing. If you've had to put even a moment's
care into that list above, than you've already wasted time and could
have been using Maven.
Now that I've gotten the soap-box speech out of the way,
read on to understand a little bit about it, including how to set it
up to do all the things in that list (and hundreds of other things)
with a few directories and a 5-6 line XML file (the 5-6 lines comes
from my formatting. It could easily be 3 lines of XML, if we're
honest.
Things To Know
Where Can I get Maven?
Maven is freely available, just like Ant, from Apache. Alternatively, many
distributions have it in their repositories. For Ubuntu, it's
sudo apt-get install maven2
This version, as
with all repository packages, is slightly out of date. But, at least
you're off and running.
How Do I Install Maven? The simplest way is, like Ant, to
unzip it, and add the bin folder of the directory to your
system's PATH variable. Alternatively, skip to the next
question and simply use your operating system's repository to install
it, if possible.
How Do I Build a Maven Project Building a Maven project
is easy, as the command never changes.
mvn
install
This is true whether it's your project or somebody elses. It's
predictable, and consistant.
To use it, ascend to the highest directory in the directory tree that
contains a
pom.xml file. That's usually the parent
project. Usually, Maven projects cascade downwards, so you might try
issuing:
mvn install
This will generate a
target directory in each project (if there are any).
Inspect the
target directory for your
.jar
or
.war, or whatever you're expecting.
If for some reason there's no
target directory in the
directory that contains the source code you're trying to build,
descend into it to the point where you're adjacent to the
pom.xml. Then, issue again:
mvn
install
How Do I Bootstrap a New Maven Project The simplest setup
requires the creation of directories as well as one XML file. But,
you'd likely create these directories and at least one XML file with
Ant, too.
Run the following on the command line. NB: I haven't translated
for Windows. I'm sure it's easy enough, there, too.
mkdir -p
myproject/src/{main,test}/{java,resources}
You can change
myproject to whatever you want.
This will create a directory structure like the following:
jlong@studio:~/Desktop/myproject$ find .
.
./src
./src/main
./src/main/resources
./src/main/java
./src/test
./src/test/resources
./src/test/java
If you're just getting started and aren't test-driven, then you can
ignore
src/test/*.
That leaves you with
src/main/{resources,java}.
Java code goes in
src/main/java. Things you'd like on the
classpath of the same artifact, such as Spring application contexts,
go in
src/main/resources.
Finally, you're going to need an XML POM file. POM standards for
"Project Object Model," I think.
It's the sole center for configuration related to your project. No
need to do includes, or externalized configuration or anything.
The simplest pom.xml looks like:
<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>com.yourproject.crm</groupId>
<artifactId>utilities</artifactId>
<version>1.0-SNAPSHOT</version>
</project>
You can copy and paste that into a file called
pom.xml, at the root of the
myproject folder
created above. You're done.
From here, so long as you're just planning on using the JDK,
etc, then this will work fine.
What do those directories and 5 lines of XML buy me?
Think of that as being equivalent to hundreds of Ant targets. The
project already has enough information to, among other things:
- Generate javadocs:
mvn javadoc:javadoc
- Compile classes:
mvn compile
- Compile and generate an artifact (a
.jar, in this
case): mvn install
- Generate a Checkstyle report:
mvn
checkstyle:checkstyle
- Or, in the alternative (and perhaps a complement): generate a PMD
report:
mvn pmd:pmd
- Build a web site with documentation on the structure of the
project (anemic thing that it is):
mvn site
- Build a cross reference of the project's sources:
mvn
jxr:jxr
- Setup project files for your favorite IDEs:
mvn
eclipse:eclipse, or mvn idea:idea (NB: if
you're using IntelliJ IDEA 7 or
later, or Eclipse with the
fabulous m2Eclipse plugin, then you don't need these plugins. You
can simply 'open' the project as you would any project by importing or
opening the pom.xml. Netbeans also has incredible
support for opening Maven projects directly.
How Do I Add JARs to the ClassPath? Short answer: you
don't. You let Maven handle it for you.
If you need a .jar, more than likely, it's already
available in some repository, in the same way that a package might be
provisioned by an operating system (such as Windows Update on Windows,
apt on Debian distributions, rpm on RedHat
distributions, port on OSX, etc..). For Maven, using a
depdendency is as simple as identifying it and adding the metadata to
the pom.xml.
There are many ways to "find" a
.jar. The simplest is to start browsing a central
repository and opening the pom.xml files. To add a
dependency, you need it's <artifactId>, its
<version>, and its <groupId>.
These elements are usually at the top of all pom.xmls. To
add a dependency on the Apache Commons Lang library
to our project above, add the following lines to your
pom.xml, right before the closing <project>
element:
<dependencies> <!-- plenty of room to add
dependencies --></dependencies>
Inside the
dependencies section, you will add all your
dependency information. The information you enter could be that for a
third party
.jar, or a
.jar in your own
project. Perhaps one team's project depends on another's. If Maven
can't find the cached version of the
.jar, it'll download
it for you.
<dependency><groupId>commons-lang</groupId><artifactId>commons-lang</artifactId><version>2.4</version></dependency>
To test, simply rebuild it as before: mvn
install. Most of the IDE integrations will have suport for
updating the project configuration in the IDE (i.e., the classpath)
according to what's in Maven's configuration. If you'd rather not
spelunk through the ibiblio repository site, you can
always use one of the many Maven repository indexes. A good one is Maven Search. Type in a
fragment of what you're looking for and it'll provide you with
matches. Thus: I entered "commons-lang" and it found results.
Additionally, most of the IDE's will have support for some form of
repository browsing.
I'm Test Driven!
This one's easy. If you do want to use JUnit (or TestNG), then
fret not - that's Maven's default M.O.! By default, any JUnit classes
put into the src/test/java folder will be compiled and
run before proceeding with the build.
The Tour's Over, What Did You Think?
In this guide,
I've given a walk through to the questions I can imagine thinking
about when setting up a project with Ant. The result is that you can
get a LONG ways with nothing (the minimal pom.xml).
The balance of a given effort is the 20% stuff. As they say,
the 20% cases can take 80% of the time. I can't speak to whether this
is true or not as Maven's never delayed me, for any particular length,
except when I was pushing it to do stuff that nothing else, including
Ant, could have done.
Even so, if you hit the 20% cases, you can rest easy in the knowledge
that Maven is built to be flexible and extendable. It's whole model is
exposed as a lifecycle. If you want to inject custom logic at a custom
point, doing so is easy. It's also insanely interoperable. In fact,
even if you don't want to use Maven but wan't to get a very high
quality build script, setup the project using Maven and then use
mvn ant:ant. It'll generate an ant script that'll handle
most things you'd want to do. Finally, if you decide you absolutely
can't live without, or translate effectively, an Ant script, there's
good support for running Ant scriptlets inside of Maven.
Go ahead and give it a try if you haven't tried it before or
if you were put off. It's truly powerful. The most visible testament
to this are the ideas (like Ivy) that are inspired by it in Ant.