warpedjavaguy

Observations of everyday programming phenomena

Archive for the ‘automation’ Category

How I defeated the maven-release-plugin in a flat structured multi module project

Rules are made to be broken so that paradoxes can be created.

Maven is a handy tool and has a lot of available plugins. It adopts the convention over configuration philosophy and provides a standard build lifecycle out of the box. This makes it very easy to automate a build and release process without writing a single line of script. But there’s a catch! It only works if you do things the “maven way” and follow the maven rules.

Most projects are made up of one or more multiple smaller projects. In the maven world, such projects are called multi module projects. A multi module project has a parent project and one or more nested child projects known as modules. When you build the parent project the child projects are also built. The recommended maven way of structuring a multi module project is to mirror the parent child hierarchy using a nested project structure.

So maven recommends that you create a parent project that contains the child projects using a physical project structure like this:

workspace/parent/pom.xml
workspace/parent/child1/pom.xml
workspace/parent/child2/pom.xml

Modules are then declared in the parent POM like this:

<modules>
  <module>child1</module>
  <module>child2</module>
</modules>

This was good for maven but it was is not good for eclipse. The eclipse IDE does not support nested projects. This was clearly a problem! I wanted to import all my projects (parent and children) into eclipse but the nested structure made this impossible. So I decided to use a flat project structure instead and moved all my child projects out of the parent project.

Now my parent and child projects were organised in a flat physical structure like this:

workspace/parent/pom.xml
workspace/child1/pom.xml
workspace/child2/pom.xml

And I then redefined the maven modules in the parent POM like this:

<modules>
  <module>../child1</module>
  <module>../child2</module>
</modules>

Now I could import all my projects into eclipse. This worked well and life was good until I decided to use the maven release plugin to automate the release process. I learned the hard way that the release plugin only supports the nested project structure recommended by maven. Reverting back to the nested structure was not an option. I had broken a maven rule and was being punished for it! I needed a paradoxical solution that would support both the nested and flat structures at the same time. It was then that I realised that my parent POM was responsible for two things: POM inheritance and module composition. It served two “parental” roles. In one role it provided all the common properties, dependencies, plugins, and profiles to all children through inheritance and in the other it defined itself as the parent project of all child projects. In OO terms, this was akin to defining a superclass that contains a list of all its subclasess.

My parent POM had violated the single responsibility principle. So I decided to split it up into two separate parent POMs. I removed the modules declaration from the original POM in my parent project. This POM was now purely to be used for inheritance purposes only. All child POMs continued to reference this POM as the parent POM. Nothing changed there. I then created a new POM that inherited this modified POM and aggregated all the other child POMs. I placed this new top level POM file in the workspace root alongside all my existing projects. My flat project structure now had a top level POM file that defined all the child projects as modules.

The final project structure looked like this:

workspace/pom.xml
workspace/parent/pom.xml
workspace/child1/pom.xml
workspace/child2/pom.xml

The workspace/parent/pom.xml was inherited by all child POMs and also the top level workspace/pom.xml. It was the parent POM for inheritance purposes. The top level workspace/pom.xml aggregated all the child projects into one container project. It was the (root) parent POM for composition purposes. It defined the parent and child modules like this:

<parent>
  <groupId>?</groupId>
  <artifactId>?</artifactId>
  <version>?</version>
  <relativePath>parent/pom.xml</relativePath>
</parent>
<modules>
  <module>parent</module>
  <module>child1</module>
  <module>child2</module>
</modules>

Both the maven release plugin and the eclipse IDE were happy with this structure. It was flat enough for eclipse and hierarchical enough for the maven release plugin.

Note: After experiencing and resolving this problem first hand I later discovered that the issue has already been reported and discussed here and mentioned at the very bottom of the maven eclipse plugin page. But I still cannot find any mention of this limitation on the maven release plugin page itself. I suspect that this is a well known issue in the maven community. If anyone is aware of any fixes or better solutions, please let me know. Interestingly also the title of this issue suggests that the problem has been fixed but the actual contents therein state otherwise.

Sample POM snippets – Posted on 22 Aug 2011 by request

workspace/pom.xml (The top level root POM)

  <parent> 
    <groupId>maven.demo</groupId> 
    <artifactId>parent</artifactId> 
    <version>1.0.0-SNAPSHOT</version>
    <relativePath>parent/pom.xml</relativePath>
  </parent> 

  <groupId>maven.demo</groupId>
  <artifactId>root</artifactId>
  <version>1.0.0-SNAPSHOT</version>
  <packaging>pom</packaging>

  <modules>
    <module>parent</module>
    <module>child1</module>
    <module>child2</module>
  </modules>

workspace/parent/pom.xml (The parent POM)

  <groupId>maven.demo</groupId>
  <artifactId>parent</artifactId>
  <version>1.0.0-SNAPSHOT</version>
  <packaging>pom</packaging>

workspace/child1/pom.xml (The child1 POM)

  <parent> 
    <groupId>maven.demo</groupId> 
    <artifactId>parent</artifactId> 
    <version>1.0.0-SNAPSHOT</version>
    <relativePath>../parent/pom.xml</relativePath>
  </parent> 

  <groupId>maven.demo</groupId>
  <artifactId>child1</artifactId>
  <version>1.0.0-SNAPSHOT</version>
  <packaging>jar</packaging>

workspace/child2/pom.xml (The child2 POM)

  <parent> 
    <groupId>maven.demo</groupId> 
    <artifactId>parent</artifactId> 
    <version>1.0.0-SNAPSHOT</version>
    <relativePath>../parent/pom.xml</relativePath>
  </parent> 

  <groupId>maven.demo</groupId>  
  <artifactId>child2</artifactId>
  <version>1.0.0-SNAPSHOT</version>
  <packaging>war</packaging>

Written by warpedjavaguy

August 8, 2011 at 11:21 pm

Posted in automation, maven

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: