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

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.

Related

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.

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.

maven sub projects - should they have their own depedencies

If a project has many sub-projects, and all the sub projects have a common parent pom.xml, shouldn't all the the dependencies be listed in parent pom.xml ?
What's the point of allowing sub project to have their own dependencies.. ? It only opens up the possibility, that one sub-project will use apache_xyzlibrary_1.0.jar and another sub project might use _2.0.jar ?
Note: All the maven sub projects combine to form a single webapp WAR.
It will be very inefficient to include all the projects dependency into every sub project as by doing that, you are effectively bring in unnecessary dependencies into every of the sub projects' build. And one other issue is if you have inter sub project dependency, i.e. sub project a depending on sub project b, then you can easily end up a cycle dependency which maven unable to resolve.
To keep the consistence of dependency versions across the project, maven's approach is to make use of the dependency management section in the project's parent pom. Hence, only set the version of every dependency in the parent pom's dependency management section. In the sub project's pom, only the group Id and artefact Id is stated. No version tag should be used in the sub project's pom unless that is needed (i.e. when a sub project required a particular version of a dependency that is different from the rest of the project)
If all the children declare the same dependency, it is a good idea to declare that dependency in the parent instead. You are right about this ensuring all projects use consistent versions of dependencies.
As for why did the Maven developers decide to allow dependencies to be declared in child projects if this makes it possible to use different versions of the same dependency? I imagine they were thinking the advantage of locally declared dependencies in projects, when they are different from sibling projects, was nicer to have than restrict the parent to declare all dependencies for all its children.
Think of it like variables declared at different scopes in a class. If you have a private variable in a method, you know that it is only used in the one method and you can change it as you see fit without needing to worry about your entire code base. If you have a private field in a class, you have to aware of all it's usages in that class but not in other files. If you have a public variable, well you get the idea. Dependencies are the same, if you have one declared for a single project, you can be certain it is only used/needed by the single project. Furthermore, it doesn't need to be present if you are building a different child project of the same parent.
As for you building a WAR, you are right, using different versions of the same dependency in different child projects will probably cause you grief with the final artifact. Just be aware that there are other project types and build cycles where have mixed version numbers between projects may not be a problem and is actually desired.
Remember too that maven parent pom files can also have parents. This allows for more tiers of a hierarchy than just 2 levels. I think it would be ridiculous if all children projects had to declare its dependencies in the top level parent project pom file.

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

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.

How should I share Maven DepdendencyManagement from multiple sources?

I have a Maven project multimodule project. Some of the modules create custom packaging for the libraries produced by the other modules. The packaging being used has its own suite of versioned dependencies that I need to play nice with.
As an example: my parent POM might have an entry for e.g. commons-codec:commons-codec 1.4, my "core-lib" POM includes it as a dependency (sans explicit version), and I want to make sure my packaging module bundles in the right version. However, the specific type of custom packaging that I'm using also needs e.g. log4j:log4j 1.2.15, and I want to make sure that when my packaging module runs, it also bundles the correct log4j version.
Here's the wrinkle: the example POM I'm working from for "project that makes {custom packaging}" uses a parent that's provided by the custom-packaging team. If I use their parent, I lose the version info for commons-codec. If I use my parent, I lose the version info for log4j.
Now, ordinarily if I ask "how do I make A and B depend on the same version", you'd answer "make A and B have the same parent, and include a dependencyManagementsection in the parent". My problem is, I need A, B, and C to depend on the same version, but I don't have any control over C.
I think this is what Maven "mixins" are meant to address, but of course they don't exist yet. In the meantime, what I've been doing is picking one parent, then copy-and-pasting the dependencyManagement section from the other POM, with a comment saying "make sure you keep this up to date". Obviously this is an ugly, ugly hack, but I haven't found another way to keep current with both sides.
What about using the assembly plugin to pack up your artifact with all its dependencies and having your packaging module run on that instead? Then you're not trying any pom magic. It's just a matter of one project using the artifact from another project, like usual.
For now, I'm going to accept the answer of "this is one of the really sucky things about Maven". Maybe this question can get updated when Maven 3.1 finally launches.
Could you not activate multiple profiles which have their own dependency section pulling in the required libraries when enabled. This allows some nice flexibility due to the ways that profiles can be activated.

Resources