Maven Hacks

January 21, 2010 - zenoconsultingzenoconsulting


Introduction

You either love Maven or hate it. There seem to be few that are in between. I like it, but I have spent a lot of time with it, and I know how to make it do pretty much anything. That said, I'm leaving this page open for maven hacks that I may use often for the interested reader. To be honest, the real reason is so I have a quick online reference when I get in this situation: I know that is possible. I've done it before. I just don't remember the exact syntax, etc.

I aim to continually update this over time.

Hack #1: Why can't I just make Maven use some Jar in a /lib folder?

You can. It isn't advisable to do this b/c it goes against the grain of the whole dependency management feature and storing jars in source control, etc., blah, blah.

You really should stand up your own local repository server and use that for a whole lot of reasons (stability, privacy, performance, determinism), but I digress…

I find I need to subvert this whole notion often because I often just build quick simple demo projects for someone that I send to them or provide as a link on this blog, and often it may include a jar that isn't publicly available. I don't really feel like asking them to set up something like Archiva just to get the project to build.

So, let's say you download some bar-1.5.jar from foo.org directly from their website b/c there is none to be found in any online maven repo. So, you can create this directory structure:

+- my-app
| +- pom.xml
| +- src
|   +- main
|     +- java
|   +- test
|     +- java
| +- lib
|   +- org.foo
|     +- jars
|       +- bar-1.5.jar
|     +- pom
|       +- bar-1.5.pom

Now, add this to your pom.xml

<repositories>
    <repository>
        <id>local</id>
        <url>file:///${basedir}/lib</url>
        <layout>legacy</layout>
    </repository>
</repositories>
 
<dependencies>
    <dependency>
        <groupId>org.foo</groupId>
        <artifactId>bar</artifactId>
        <version>1.5</version>
    </dependency>
</dependencies>

Now, fill in the file bar-1.5.pom with something like this:

<?xml version="1.0" encoding="UTF-8"?>
<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>org.foo</groupId>
    <artifactId>bar</artifactId>
    <packaging>jar</packaging>
    <version>1.5</version>
</project>

We're just tricking mvn into thinking it has to deal with the old legacy style repos which is really just a local file url. Voila!

Hack #2: Tips for converting Ant to Maven

I've converted a number of Ant builds to Maven builds. The first thing you need to do is figure out what all the dependencies are. Typically the project will have a /lib directory or maybe more than one. Let's say you have a directory like this:

+- my-app
| +- lib
|   +- foo.jar
|   +- mystery.jar

What is mystery.jar? You might even open it and look at the MANIFEST.MF if there is one, but lo and behold they didn't supply one. So, you can then try to guess what it is by the package namespace, but even if you can track it down to a website, you still may not know what version it is.

That's why maven stores an MD5 with each jar in a maven repo. So, fire up a terminal and do:

$  md5 lib/mystery.jar
MD5 (mystery.jar) = ef65a49a1e3ae5fb59cde275d0c3f666

If you're on Windows, there is a really great Explorer shell integration that allows you to right-click a file and calculate the MD5 and paste to the clipboard. It is called digestIT from Colony West Software.

Now, throw that hash into a Google search and see what pops up. If it leads you straight to an online maven repo, the chances are mathematically in your favor that you've discovered what your mystery jar is.

If you didn't find it…you'll have to deploy it to a local repo manager and name it something that makes sense, with a canned version number like "VERSION_UNKNOWN". When the migration to maven is complete, and you get all your tests to pass — you can try upgrading each of these jars one by one.

Hack #3 How to Share Resources Across Multi-Module Projects

If you didn't know it already, maven allows you to break up your code into hierarchical project structures. Parent pom.xml files may not contain source code but act as a way to share common aspects about how the project is built and what its dependencies are. A typical example of this kind of scenario is where you have a layered architecture and the upper layers share several components below. You want to avoid copy/paste, right? And you want to avoid having it all built in the same monolithic behemoth project space, right? So, you chop it up into multi-module maven projects.

This works quite nicely until you realize that lots of code in these different projects depends on the same configuration files (e.g. spring context or properties files, test files, etc.). Now, you've copy/pasted this into every project that needs it. This is a nasty problem. Consider the spring context. You change it in one project, and that affects code in another project, but you won't know this until you run some kind of integration test. So, you detect the failure, now you have to go make changes to it in every project.

This is annoying and wrong. The solution is to move your shared resources out into its bona-fide project. Make all your projects that need those resources depend on it, and use maven's assembly and dependency plugins to make sure those resources are on your classpath or your test classpath — wherever you need them. You can also filter out only those resources you actually need. This is all handled in the mvn build lifecycle for you if you set it up right.

I can't take credit for this one since I stole it from Brian Fox's blog over at Sonatype. Full solution is over there, and you should be able to follow the logic / examples there pretty easily. If you ever find the link broken, let me know, and I'll do a write-up here on how to do it with the plugins.


Backlinks


Add a New Comment
or Sign in as Wikidot user
(will not be published)
- +
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License