Fork me on GitHub

January 17, 2010

The Maven Plugin War

Post moved to

I guess, everyone who did a project beyond "Hello World" in maven feels the same - it's a love/hate relationship. To be fair most of the times it's all those battles with the plugins that You need to fight.

This particular one is all about the maven-war-plugin. The war plugin is another of those often betas and it's better that way, otherwise we could actually blame it !
Let's suppose You would like to package Your webapp but just before making the war You would like to change a thing or two. Doesn't matter what, but to explain let's say You would like to change a web.xml context parameter value (e.g. for a production environment). And here's the "impossible" requirement: You can't use maven filtering, the default web.xml with all it's glory have to stay the way it is (usable for deployment out of the box).

The first thing that a maven ninja would think of is to bind to a phase where the project is already pre-packaged to make the changes required and then let the war plugin finish it's packaging work. Now days You can't - the war packaging all happens in a single phase. Feels wrong, but whatever, let's take a closer look by digging into the plugin. There's an interesting aspect of how resources are handled. If web resource directories are specified and they contain the same file the first one found will be packaged. In other words when the plugin copies a resource to be included in the archive it checks if it's already there and if so it skips the file. And luckily web resources are handled before the war source directory.

To demonstrate this concept, let's face a concrete requirement. Suppose we have a web application descriptor similar to this one :

And would like to have the SOME_PORT parameter value changed to a configured value in a production profile.

We'll use gmaven plugin for the job, without more chit-chat here's the POM :

Notice how a resource directory is configured in the profile, that's the directory that will contain the updated web.xml with SOME_PORT changed to 80. Of course the directory does not exist, it's the gmaven goal that will create it during the generate-resources phase. The war goal will run after - during the package phase.

To be complete here's the referenced script that creates the resource dir and the updated web.xml (should be placed inside the project's base directory) :

The groovy code should be self explanatory. The only snag for first time users of gmaven might be the project, ant and log references, these are setup by the plugin as hooks to the maven runtime. See the documentation for more information.

I hope I made the point, a similar setup is usable for changing the content of any resource before packaging. Sure it feels like reinventing the wheel, hopefully maven 3 will get more flexible. Until than for the next project I'll definitely try out gradle or buildr, depending on which leg I get out of the bed that morning.

No comments:

Post a Comment