Question

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:

  • bigsystem@1.2
    • parent-1.1-SNAPSHOT
    • module a@1.4-SNAPSHOT
      • parented by parent@1.1-SNAPSHOT
    • module b@1.3-SNAPSHOT
      • parented by parent@1.1-SNAPSHOT
      • depends on a@1.1
    • module c@1.1-SNAPSHOT
      • parented by parent@1.1-SNAPSHOT
      • depends on a@1.2
      • depends on b@1.1

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 a@1.2, that anytime we step into one of a's classes, it should open it from a-1.2-sources.jar rather than the current a@1.4 sources in the project. This is further confused by the fact that stepping into any of b's classes takes us to b@1.1 rather than b@1.3.

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?

Was it helpful?

Solution 3

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

  • bigsystem@1.2
    • parent-1.1-SNAPSHOT
    • module a@1.4-SNAPSHOT o parented by parent@1.1-SNAPSHOT
    • module b@1.3-SNAPSHOT o parented by parent@1.1-SNAPSHOT o depends on a@1.1
    • module c@1.1-SNAPSHOT o parented by parent@1.1-SNAPSHOT o depends on a@1.2 o depends on b@1.1
    • distribution a@1.2-SNAPSHOP

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.

OTHER TIPS

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.

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.

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?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top