Don’t Fight Maven
I’m not here to tell why I don’t like Maven or what’s wrong with Maven. Google around and you’ll easily find many. I just want to share a…
I’m not here to tell why I don’t like Maven or what’s wrong with Maven. Google around and you’ll easily find many. I just want to share a few tidbits about Maven.
So here’s My typical relationship with Maven:
When starting a new project, get an old POM from previous projects.
Everything’s fine, great! Leave it alone. Done.
Okay, something’s new. Google solutions…
Most of the time, there ARE solutions to my new build requirements. But strangely, there are also ALWAYS some tweaking needed.
Done. Leave it alone.
Until next time…
It’s especially interesting how often the above 3rd and 4th points happen. When using Maven, I found myself constantly need Google (and StackOverflow). That should say something already.
Anyway, I’ve long since learned my lesson (and you probably have already read this somewhere):
Don’t fight Maven
Multi-Module Projects
Maven believes the complete project, including all modules, should be located in a single repository. Modules are put in sub-directories.
“That can’t be right”, you said. “We have to put each module in its own repository.”
It’s a good and valid cry. But usually it ends up spending many hours hacking around.
Remember: don’t fight Maven.
One way is to use Git submodules and to create a new aggregate parent project. Maven would then take care of the module dependencies appropriately. Also, with a little change, you don’t really need an extra aggregate project simply for Maven.
Let’s use a very simple example: a web project A uses jar project B. A and B both are put in their own Git repository. How should we use Maven for them?
We can use a aggregate multi-module POM as the parent which includes both A and B as modules. This aggregate POM is put in A (named pom.xml
), as it would be the starting point for A. The POM of the actual A (the web project), named pom_A.xml
, is also put in project A along with pom.xml
. pom_A.xml
is the real deal, responsible for building web project A itself.
Project B is then added as a Git submodule in A, under sub-directory lib/B
. In pom_A.xml
, we have declared the dependency on B as usual. And that’s it.
<! — pom.xml →
<groupId>…</groupId>
<artifactId>…</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>…</name>
<packaging>pom</packaging>
<modules>
<module>./pom_A.xml</module>
<module>lib/B</module>
</modules>
<build>
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>2.5</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
…
<! — pom_A.xml →
<groupId>…</groupId>
<artifactId>A</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>A</name>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>…</groupId>
<artifactId>B</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
…
<! — pom_B.xml →
<groupId>…</groupId>
<artifactId>B</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>B</name>
<packaging>jar</packaging>
…
One caveat is the skipping of clean phase of the aggregate POM itself. Without this extra configuration, if you use mvn clean package
to build, you’d be surprised to see after A and B are built successfully, the build artifacts are cleaned immediately! Like I said, always tweaking…
One more thing is to remember to run git submodule update --init --recursive
first. I probably should Google how to include this into Maven as well…
Dependencies Not In Any Maven Repository
How should a private library be handled in a Maven build?
One choice would be to setup an internal Maven repository. If that is overkill, use a local repository in the project and have the private library also checked in.
First install the private library into sub-directory lib
(which will serve as the local Maven repository). Add the created repository files/sub-directories into SCM.
Then add to POM an extra repository pointing to sub-directory lib
. Declare the usual dependency. Done.
<! — install_lib.sh →
mvn org.apache.maven.plugins:maven-install-plugin:2.3.1:install-file \
-Dfile=./cglib-nodep.jar \
-DgroupId=cglib \
-DartifactId=cglib-nodep \
-Dversion=2.2.3 \
-Dpackaging=jar \
-DlocalRepositoryPath=lib
<! — pom.xml →
<dependencies>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>2.2.3</version>
</dependency>
…
</dependencies>
<repositories>
<repository>
<id>local-repo</id>
<url>file://${basedir}/lib</url>
</repository>
</repositories>
…