Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle sub projects dependencies in Maven

Tags:

java

maven-2

My project is made of 5 sub projects. One is a War, and the other 4 are jars. Basically the war project needs all 4 jar projects, and their dependencies.

I can strip down the dependencies to have something like war->A->B->C->D. Every sub project add their share of external dependencies (spring, struts, hibernate) so that in the end the war gets everything needed to run.

This looks pretty well organised and square, but then I ask myself if this is very practical to make changes.

Imagine I have to change one line of code in project D, without changing anything to its Maven dependencies. I would have to re-release project D obviously, but then I have to re-release projects C, B, A, and the war just to reflect this change in their pom files. This can be long and annoying, especially if you have to quickly release a new version to fix something in production.

I could make the war depend on all 4 projects, so then I just have to change project D version number in the war pom file. But then I have project A depending indirectly on project D 1.0 and the war specifying project D 1.1. I think that the war direct dependency would win in that case wouldn't it ?

This would make the new war release quicker, but it would also mess my sub projects dependencies, as they would be outdated.

What would be an acceptable way to handle this situation ?

like image 690
IceGras Avatar asked Sep 07 '10 14:09

IceGras


1 Answers

There is no simple answer to your problem.

If you indeed do have a chain of transitive dependencies (A->B->C->D), then releasing each modules up the chain independently is not a bad option. Although it is tedious, there is a good chance your nested dependencies are simple lib jars and will not see changes too often. Hopefully you will not be forced to go through that process frequently. Pretend it would be the same situation as if log4j was updated and all of your modules needed to be updated as well.

Another thing to consider is your WAR's dependencies. Yes, Maven will pull dependencies in automatically for you but it is often a good practice to declare your known dependencies explicitly so you can specify a version number yourself for each module. This would mean A depends on D and the others directly. Unfortunately, if you have conflicting version numbers, as you've described, then you are looking for trouble on your classpath. If you really need to do this though, maven does allow you exclude transitive dependencies explicitly:

<project>
  ...
  <dependencies>
    <dependency>
      <groupId>my.project</groupId>
      <artifactId>module-B</artifactId>
      <version>1.0</version>
      <exclusions>
        <exclusion>
          <groupId>my.project</groupId>
          <artifactId>module-C</artifactId>
        </exclusion>
        <exclusion>
          <groupId>my.project</groupId>
          <artifactId>module-D</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
    <dependency>
      <groupId>my.project</groupId>
      <artifactId>module-C</artifactId>
      <version>1.0</version>
      <exclusions>
        <exclusion>
          <groupId>my.project</groupId>
          <artifactId>module-D</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
    <dependency>
      <groupId>my.project</groupId>
      <artifactId>module-D</artifactId>
      <version>1.0</version>
    </dependency>
  </dependencies>
  ...
</project>

Here is the documentation describing these optional dependencies and exclusions.

Do you actually need to release B, C, and D independently? If not, consider using an Aggregator pom.xml file at the root of your modules. This will allow you to use SNAPSHOT versions throughout your modules and then release the bunch at once. This is the way our team manages our multi-module project. Using SNAPSHOT dependencies ensures you use the version that was JUST built when those artifacts are needed.

like image 97
Jesse Webb Avatar answered Oct 20 '22 01:10

Jesse Webb