Maven - include all submodules of a pom as dependencies in another module - maven

We have a maven module that is set up as so:
a (parent)
-> b (submodule)
-> c (submodule)
-> d (submodule)
This list of submodules is set to grow as time goes on (to a list of 20 or so). We have another module that will include as dependencies all submodules of a. Is there a neat way of doing this, rather than having to manually keep the submodule list in sync with the dependencies list. I.e. is there any way of including a and all submodules as a dependency?

You have a few choices here:
No change. List all dependencies in each pom. However, if they have a common parent, you can use dependencyManagement in the parent pom to set the versions for the different dependencies. In the child poms, you do not need to list the version. See this section from Maven By Example. A downside of this approach is that you have to re-list the same dependencies over and over.
Create a parent pom which lists all shared dependencies. See an example here. A downside here is you are restricting all projects that want to take advantage of this to use a parent project when they may need to use another parent project for some reason.
Wait for Maven mixins, which last I heard were still not ready.
Rethink your design. Does it make sense for projects to depend on so many different modules and interfaces? To reduce coupling, you may want to create one interface that these new projects can use. Several open source multi-module projects, such as Apache Axis2, follow this pattern. One module contains your 20 dependencies and exposes an interface which the new modules can call. The new modules can just list that one main module as a dependency and all of the 20 dependencies are pulled in as transitive dependencies.
I think choice #4 is probably right, but I am not familiar enough with your situation.

Design considerations aside, this is easily done - simply include <type>pom</type> in your dependency pointing at the parent pom. E.g:
<dependency>
<groupId>my.group.id</groupId>
<artifactId>a</artifactId>
<version>0.0.1-SNAPSHOT</version>
<type>pom</type>
</dependency>

The only way dependencies get "automatically" included is via the transitive dependency mechanism, and it only works by pulling in dependencies of dependencies, so unless you have a pom that depends on all the submodules, no, you won't get them without listing them all out. A need to do this points to a flaw in your project design. If the modules are "all or none", then they're probably not separate modules.

Related

Should exclusions be handled in the child pom or parent pom?

I am commonly in this situation where I am working on a couple of projects that all depend on the same parent pom. We handle all of our dependency versions and exclusions in the dependencyManagement section of the parent pom. The child poms will specify the dependencies they need but they will use the version from the parent.
When we place an exclusion on a jar, it is generally because we are wanting to get a different version of that jar from somewhere else (typically a different jar we depend on).
However, I ran into a problem. Lets say you have two jars A and B in the parent that depend on different versions of jar C. Someone working on a child project may need both jars A and B and then might go into the parent, excluding jar C from jar B. This may work out fine for them. However, someone else who is working on a different child project may only depend on jar B and now their project might get a NoClassDefFoundError at runtime after they pick up the latest parent code due to losing jar C. Now, maybe a 3rd person who is later working on a different child project decides they need jar B (and not jar A) so they add jar B. If they don't pay careful attention, they may not realize that they don't have jar C which is needed by jar B. At runtime they might get a NoClassDefFoundError.
As you can see, any child project that needs both jar A and jar B are fine but any child project that needs only jar B needs to remember to add jar C to their pom too.
Is it better practice to only do exclusions in the child pom? Or should I continue trying to have exclusions in the parent pom and make sure to just look closely at the exclusions and add additional dependencies to the child pom as needed? Thanks!
Use dependencyManagement in the parent for versions only, not for exclusions (and not for scope). As you point out yourself, adding exclusions in the parent can lead to situations where other developers (and maybe even yourself at a later point in time) get confused about why they don't get the necessary and expected transitive dependencies.
Regarding:
When we place an exclusion on a jar, it is generally because we are
wanting to get a different version of that jar from somewhere else
(typically a different jar we depend on).
You can enforce the correct version for these transitive dependencies in your parent pom as well to avoid exclusions for the reason you give here. The downside is of course that you must remember to update those versions when you update the version of the dependent library. This is how we manage our project with >200 poms, and I must say it's far better than figuring out where to add excludes to hopefully get the correct version of all the dependencies.

Module inheritance vs aggregation

We have a big and deep module structure with three "real" layers of inheritance and three to four layers of module aggregation.
I am fine with the real inheritance: a company wide super-pom, a product-wide parent and a customer-wide parent for customizations of the product.
But I observe that also the "empty" aggregating modules are defined as parents of their submodules.
If the whole concept is the same as in OO, this makes no sense to me if the aggregating modules (they are empty besides their submodules) add no specific configuration to the pom.
Is there any other reason (perhaps operational) why this could be useful?
Sidenote: Introduction to the pom is not clear in this respect: term "parent" is not clear: it can mean super-pom (=parent in inheritance tree) or aggregating pom (=parent in filesystem...)
There is a great problem in the definition of these concepts in the Maven community. You are right with stating that a parent-pom is inheritance and module-pom is composition. But unfortunately the separation of these two concepts have no history in Maven. The Maven documentation says clearly that it is better to separate them. This would result in this ideal structure
app-api/
app-impl/
app-war/
app-parent/
pom.xml
Where pom.xml is the module pom.
But almost every project you will see in the open source sector does not distinguish between them.
This has a reason: Many plugins do not distiguish between them as well. And even Maven itself assumes another setting: If <relativePath> is not set Maven assumes that the parent is at ... So every project has to point to <relativePath>../app-parent</relativePath> as parent.
The most popular plugin that has huge problems with the mentioned structure is the maven-release-plugin! You will face strange problems when you do not follow the assumption that the module-pom is the parent-pom.
The worst bug is that the release-plugin cannot replace version-properties in your parent and fails because of SNAPSHOT-Dependencies. Your parent perhaps will contain something like this
<properties>
<app-api.version>1.1-SNAPSHOT</app-api.version>
<app-impl.version>1.2-SNAPSHOT</app-impl.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>myorg</groupId>
<artifactId>app-api</artifactId>
<version>${app-api.version}</version>
</dependency>
<dependency>
<groupId>myorg</groupId>
<artifactId>app-impl</artifactId>
<version>${app-impl.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
Normally while releasing these properties would automatically be set to their release versions 1.1 and 1.2. But the release-plugin (tested up to version 2.2.2) fails with a message that the module cannot be released with snapshot dependencies.
If you only "skip" some module-poms this might not be a problem when you define <relativePath> correctly. But you have to try and expect some bugs in Maven plugins. Besides these bugs you are totally right to seperate the poms and I would give it a try if you have the time to make a sandboxed release.
The short answer IIUC is, you don't inherit from your aggregation-only poms. You do when your aggregator is the same as your parent, as in the canonical maven structure. But if you separate aggregator from parent, don't inherit from the aggregator
The inheritance of a parent pom is usefull if you have properties that are valid for several projects. From what I understood you already got that part right ;-)
What you call aggregating modules has a valid practical use too. You can group several submodules into a single pom. If you want to build your project you mostly don't want to build every module sperately but join them into one single application. This can be done by such a pom that references all the submodules as such. It can't be done with just the concept of a parent pom as it knows nothing of the other modules.
Adding an eclipse perspective here :
when you create maven module within a maven project using eclipse IDE's wizard, by default, the new module will created as child of top level project and also top level project will be an aggregation of child.

How to handle two Maven submodules that share a code dependency

I have what I think is a fairly common setup. I have a project with two modules, each with its own pom.xml. Above that, I have a pom.xml for the project, which depends upon its submodules. The two submodules have a shared dependency, namely log4j. How should I deal with this dependency? Should I simply just have each submodule have log4j as a dependency, or should the higher level project module get involved, claiming it as a project dependency? If I have both submodules listing the dependency, will Maven be smart and only pull down log4j once, or will each submodule pull down its own private copy of log4j ? If the project module has the dependency, will the log4j package be available at the right time for the submodules? What would you do, or what have you done in this situation?
The best way to do this is with the dependencyManagement tag.
The dependency management section is a mechanism for centralizing dependency information. When you have a set of projects that inherits a common parent it's possible to put all information about the dependency in the common POM and have simpler references to the artifacts in the child POMs.
To summarize the effect, you put the tag in the parent pom and have the children refer to it. They don't refer to the version number though. The benefit is at any time you can update the version of log4j in the parent pom and all your child poms get the new version without modifying their poms.
You are able to set the dependency at the higher level project. This will cover the dependency for both modules of your project.
Source: This is what my team does in one of our projects.

Maven Modules vs Stand Alone Maven POMs as dependencies

I currently work on a project which comprises approximately a dozen sub-projects.
Each sub-project contains a POM which builds the dependency seperately.
Upstream sub-projects include the downstream sub-projects as dependencies in the same way that you would include a dependency on something like log4j:
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
We hold these dependencies in a local Nexus repository.
This seems to work for us.
However I have today, after 11 months of development, decided to revisit these dozen POM files with refactoring in mind.
I have subsequently discovered the <parent> and <module> tags and am starting to question if my Maven project strategy is 'right'.
What benefit would there be to refactoring my POMs such that the upper-most level POM (a Web WAR project) is changed into a Parent POM which lists modules rather than a series of dependencies as above?
I would I anticipate most of the dozen sub-projects to take on a lifecycle in their own right, such that they would be available within the company's Nexus repository as code libraries for other company projects.
For example, is it the case that one uses a multi-module approach to break up and organize the composition of a sub-component of a project? Or would one take a module to represent an entire component of a project?
Thanks for everyone's views so far - I realise this question is subjective.
After a while it seemed to me that the 'right' answer to this question would be determined by another question: Do each of the subprojects take on a lifecycle of their own?
I suppose we could use UML class aggregation and composition as a metaphor. If a subproject (leaf node to borrow a term from #yorkw) cannot exist on its own or have a lifecycle of its own outside the scope of the parent project (be that a WAR, an EAR, whatever) then I would say IMHO that the structure would warrant the use of modules in a parent POM.
Otherwise, since the project can stand on its own two feet, I would say (again IMHO) that the structure would warrant an inclusion of this project as a dependency on its parent.

Adding a set of dependencies in maven

I have read how to take a jar file that I have and add it to the dependency system in maven in this link
But what i want is, I have a set of 30 to 40 jar files that I have to add to the dependency system. Do i need to add all the jar files by using the
mvn install:install-file -DgroupId=com.stackoverflow... -DartifactId=yourartifactid... -Dversion=1.0 -Dpackaging=jar -Dfile=/path/to/jarfile,
followed by,
2.
<dependencies>
...
<dependency>
<groupId>com.stackoverflow...</groupId>
<artifactId>artifactId...</artifactId>
<version>1.0</version>
</dependency>
...
</dependencies>
or is there a simple way by which i can wrap up all the dependent jar files into one maven project using mvn:install, to which my main project can be made dependent?
Thanks in advance.
If most of the 30-40 jar files you are referring to are standard open source libraries, then you would not need to install them to your local repository manually. It is also possible that many of them are transitive, i.e. one dependency in turn pulling in another. In this case, you would need to only add as dependency the primary dependencies. This will in turn pull in the transitive ones.
If most of the dependencies are proprietary and you manage them yourself, then chances are you have them in your source code management system in some specific folder, say lib. If so, you can skip the install step and just specify dependencies using <system> scope (refer here).
You could define a single maven project (as pom type) to specify all the dependencies and have your main project dependant on it, if that simplifies things.
The first answer in this link really solved my doubt..
"Projects should explicitly list all their dependencies and not rely on inheriting them (IMHO). It means you have to declare your logger a few times but it will save you pain later. (You can of course use a separate POM project to group together dependencies that are related and hence usually specified together, like the hibernate example in your link). If you want to centralize versions of dependencies, you can put a dependencyManagement section in the parent POM, which means you still declare the dependency in the child project, but the version comes from the parent, thus ensuring consistency. Children that don't declare the dependency don't end up with it at all."
So the practice should be to create separate POM (Child) project for all the dependencies, and if we want, we can wrap them up using aggregation to a Parent-POM which can be referred singly in our project. But we have to however create a child project separately for each dependent JAR. Bit time taking process, but seems to be the only answer.

Resources