views:

760

answers:

4

I'm trying to work out the best way to setup our multi-module Apache Maven project in a way that allows for disparate release cycles of modules, and doesn't introduce dependency issues when debugging the project.

We currently have a setup along the lines of:

The dependencies declared in modules b and c contain the minimum version required to compile the module, which isn't necessarily the current version of the module, or the version of the module being deployed.

From a build perspective this works well, each module can be released/updated as needed, however when trying to debug the deployed application under IntelliJ IDEA (versions 8 and 9 EAPs) having opened the top level pom, IDEA decides that since we declared a dependency on [email protected], that anytime we step into one of a's classes, it should open it from a-1.2-sources.jar rather than the current [email protected] sources in the project. This is further confused by the fact that stepping into any of b's classes takes us to [email protected] rather than [email protected].

My initial attempt to work around this was to declare the version numbers in the parent pom's dependencyManagement section and just have the sub-modules inherit the version. This worked to the degree of solving the IDEA debug issue as the dependencyManagement section can point everyone to the current -SNAPSHOT versions.

This unfortunately causes a problem when doing a maven release due to having to release the parent pom before releasing the module, but as the parent may refer to multiple in-development -SNAPSHOTS it can't be released and we end up adding version references back to the modules pom to satisfy the release.

It would seem that using maven's dependencyManagement section would only really work well if we were releasing ALL bundles at the same time, regardless of if they changed, but as we're wanting to manage releases of each sub module only when needed this model doesn't seem to fit.

I have a suspicion I'm missing something, and that a combination of dependencyManagement and version ranges might satisfy out requirements although I've yet to see version ranges work properly.

Is there a better way? A proper way?

+4  A: 

I would recommend not making them modules, but make their POMs independent. That way you do not have to worry about trying to satisfy parent POM dependencies. Since they are released independently, they really should have independent project object models. Think of Apache Commons as a template.

Rob Di Marco
Hmm, even if the POMs for each sub project were independent, I'd still have them referred to from the toplevel pom so that the whole project could be built or opened by IDEA/Netbeans - which still gives the debugging issue or version mismatch. I suspect the problems I'm having are two fold - whilst they're released independently they're deployed together as a system, not separate standalone projects, and more in that when debugging, there's no version information available about WHAT version is running.
Mark Derricutt
On further thought, I suspect the problems I'm facing with version ranges here is that our CI tool is building/installing the top-level module whenever ANY module is changed, which will install a -SNAPSHOT version of all modules, even if they're freshly released, but unmodified. If, as you suggest I remove the multi-module build and configure the build server to watch each module individually this should help solve the release issues.
Mark Derricutt
Definitely break your modules into their own top-level projects. Modules are meant to be built and released together.Also, consider leveraging something like Hudson's automatic rebuilding as determined from Maven dependencies (http://weblogs.java.net/blog/johnsmart/archive/2008/11/managing_automa.html) to ensure changes in lower-level dependencies are automatically propagated and rebuilt with the higher-level ones.
Brian Laframboise
A: 

They certainly seem like separate modules. What benefits are you gaining by smashing them together if they have different dependencies, even within the multi-module project?

Nick Veys
In this instance, the parent POM defines standard plugin configurations such as including the maven-felix-bundle and maven-felix-scr plugin. I wouldn't called them "smashed together" thou, each module declares its own dependencies - external dependencies can easily be dealt with in dependencyManagement where they don't often change, the problem I'm having is with the versions of my own modules.
Mark Derricutt
+1  A: 

I think the problem with IDEA arises because you are using the root POM in your source structure to do two things that are usually mutually exclusive in Maven. You are first using the POM as a location to store common configuration information for unrelated (from a build perspective) Maven projects. Secondly you are using the POM as an aggregator for your build. You can do each of these without doing the other.

Like Rob said, remove your module a, b, etc. projects from the modules section of your parent POM. Secondly, move your parent POM down into its own directory as it is really a sibling of the other modules with respect to your build and release process. The way you have it now, it is more of a parent/aggregator.

The way you have it now also doesn't lend itself to tagging and releasing each module individually as a tag of your parent POM would likely needlessly include all of the module sub-folders.

Your file structure would look like:

  • parent
    • pom.xml
  • module a
    • pom.xml
  • module X
    • pom.xml

As for the thing you are missing, dependencyManagement isn't really well suited to manage versions for intra-project dependencies. That is dependencies between modules within an aggregated build. It is more well suited for declaring global versions for external dependencies.

DavidValeri
Good comments, however - it seems you and other commenters think my root POM contains my common config. I mentioned adding that to the parent POM which is at the same layer as my modules, much as you show in your structure, with the root POM above them all.
Mark Derricutt
+1  A: 

The final/working solution we ended up using was fairly similar to what we started with. The actual project structure remains the same:

However the main differences are that:

  • parent module does not include any versions of project artifacts
  • individual modules fully declare their project dependencies and specify a version range, i.e. [1.0.0,1.1.0)
  • all modules start there version number cycles from .1, i.e 1.0.1-SNAPSHOT, this allows the version range to satisfied by initial snapshots (1.0.0-SNAPSHOT is earlier than 1.0.0 final, so not included).
  • distribution pom (not initially shown in question) identifies the exact version to be deployed/included in a specific release.
  • delete all project -SNAPSHOTS from local maven repository when releasing so that ranges pickup releases only ( or use -Dmaven.repo.local=/tmp/sometemprepo for a fresh local repo)

This makes each module more standalone and gives us the freedom to release and deploy new versions of our project artifacts with minimal fuss.

Mark Derricutt