Maven parent POM vs BOM dependency management - maven

Let's say I have a maven parent POM root which defines foo:bar:1.0.0 in dependency management. I have another parent POM parent which uses root as parent (just to add another layer to the example). Lastly I have a bill of materials bom which uses root as its parent but redefines foo:bar:2.0.0 in its dependency management.
In my project app I inherit from parent and then I import the BOM in the dependency management section of app
root (foo:bar:1.0.0) <- parent <- app+bom
^
|
bom (foo:bar:2.0.0)
Which dependency management section wins? Which version of foo:bar do I get?
I know that if I were to directly include foo:bar in the dependency management section of app, it would override that inherited from the parent. But is importing a BOM in the dependency management section equivalent to directly including it in the dependency management section, and sufficient to override that of the parent? Or does the inherited foo:bar from the parent's dependency management take precedence?

According to the maven precedence rules, the version from the root will win and therefore you will get foo:bar:1.0.0, which you will be able to see if you look at the effective POM. I think that this makes a BOM project less effective since you cannot use it to override the version from the parent and have to declare the version in the app or in the parent.
The Precedence
So, there are multiple ways of deciding the versions,
which means there is an order of precedence.
Versions provided in the direct declaration in POM take the highest precedence.
Version provided in parent pom takes second precedence.
Version from imported pom takes third place
Lastly, whatever we get from dependency mediation

Related

Should I rely on transitive dependencies in Maven if they come from other sub-module of my parent?

Suppose we are working on mortgage sub-module, and we are directly using the Google Guava classes in module code, but the dependcy for the guava is defined in other sub-module under the same parent and we have access to Guava classes only by transitive dependency on "investment" module:
banking-system (parent pom.xml)
|
|-- investment (pom.xml defines <dependency>guava</dependency>)
|
|-- mortgage (pom.xml defiens <dependency>investment</dependency>)
Should we still put a <dependency> to Guava in the mortgage pom.xml?
The cons looks like duplication in our pom.xml, the pros are: if someone developing "investment" will drop guava, then it will not stop our mortgage sub-module from being successfuly build.
If yes, then what <version> shoudle we specify? (none + <dependencyManagement> in parent pom?)
If yes, should we use a <provided> scope in some module then?
Note: Keep in mind, that I am asking in specific situation, when modules have common parent pom (e.g. being an application as whole).
Maybe this structure was not the best example, imagine:
banking-app
banking-core (dep.on: guava, commons, spring)
investment (dep.on: banking-core)
mortgage (dep.on: banking-core)
Should still Investment explicitly declare Spring when it use #Component, and declare Guava if it uses Guava's LoadedCache?
we are directly using the Google Guava classes in module code, but the
dependcy for the guava is defined in other sub-module under the same
parent and we have access to Guava classes only by transitive
dependency on "investment" module [...] Should we still put a to Guava in the mortgage pom.xml?
Yes, you should declare Google Guava dependency in your module and not expect it to be available as transitive-dependency. Even if it works with the current version, it may not be the case anymore in later versions of direct dependencies.
If your code depends on a module, your code should depends only directly on classes of this module, not a transitive-dependency of this module. As you mentioned, there is no guarantee that the investment module will continue to depend on Guava in the future. You need to specify this dependency either in the parent's pom.xml or in the module itself to ensure it will be available without relying on transitive dependencies. It's not duplication as such, how else can you tell Maven your module depends on Guava?
I do not see any situation in which minimal best practices are respected where you would need to do otherwise.
If yes, then what <version> shoudle we specify? (none + <dependencyManagement> in parent pom?)
Yes, using <dependencyManagement> in parent and using a <dependency> in your child module without version is best: you will make sure all your modules uses the same version of your dependency. As your modules are an application as a whole, it is probably better as it will avoid various issues such as having different versions of the same dependency being present on the classpath causing havoc.
Even if for some reason one of your module using the same parent requires a different version of our dependency, it will still be possible to override the version for this specific module using <version>.
If yes, should we use a scope in some module then?
Probably not, having the dependency with a compile scope is the best wat to go with most packaging methods.
However you may have situations where you need or prefer to do this, for example if said modules requires to use a runtime environment specific version, or if your deployment or packaging model is designed in a way that demands it. Given the situation you expose, both are possible, though most of the time it should not be necessary.
Yes, declare the dep. It's not a duplication!!! That compile dependencies are transitive is not intended by the maven developer, it's forced by the java-language. Because features like class-inheritance forces this behavior. Your already mentioned "pro" is the important fact.
See the (*) note in the transitive-scope-table
Yes, always declare needed third party lib-versions in your reactor parent with dependencyManagement. It's a pain to find errors from different lib-versions at runtime. Avoid declaring versions of third-party libs in sub-modules of large reactors, always use a depMngs in parent.
No, i would use "provided" only for dependencies provided from the runtime, in your example tomcat/jboss/wildfly/.. for things like servlet-api/cdi-api/. But not for third party libraries.
Declare the "provided" scope as late as possible (i.e. your deployment(s) module war/ear) not in your business modules. This makes it easier to write tests.
For example:
investment (depends on guava scope:=provided)
mortgage (depends on investment, but don't need guava himself)
--> mortgage classpath doesn't contain guava.
If you write a unit-test for mortgage where classes involved from investment it will not work -> you need to declare at least guava with scope=test/runtime to run these tests...
When a module uses a 3rd party library, the module should explicitly depend on that library in its pom.xml too. Imagine if another project should use the 'mortgage' module, and doesn't depend on Guava already, it will fail e.g. when a unit test comes upon a code path that involves Guava. An explicit dependency also covers you against the scenario where you refactor the 'investment' module so that it doesn't use Guava anymore. Your 'investment' module should be agnostic to such changes in its dependencies.
It's always correct to explicitly list your direct dependencies. When it comes to version, it's best to keep that in the dependencyManagement section of your parent pom so all child projects inherit that (same) version.

Spring boot parent pom with custom parent

I read a lot of posts regarding the ways to use spring-boot-starter-parent in a spring boot project.
Essentially, I read posts (Spring documentation also talks about this) describing two ways to do this
To use spring-boot-starter-parent as the project parent directly. It gives us the benefits of having the dependency management as well as the plugin management.
The other way is to import the spring-boot-starter parent in the project pom (we may need this in case we already have a parent pom for the project).
It allows us to get the benefits of dependency management but not the plugin management)
I am creating a new Maven multi module project. Ideally I would like to have my own custom parent and also get all the benefits of using the Spring-boot-starter-parent.
I was wondering if it made sense to create a custom parent for my maven projects. This parent would in turn be a child of the spring-boot-starter-parent.
If I am not missing anything, this way I could get the benefits of having the dependency management and plugin management from spring-boot-starter-parent and at the
same time have a custom parent for all my projects where I could define some other common dependencies or if needed override the dependencies defined in the
spring-boot-starter-parent which would then be inherited by all my projects.
Does this design make sense or am I missing something.
What are the drawbacks of this approach?
There are no drawbacks -- this is exactly what you're meant to do if you want a multimodule spring-boot project. However, consider this: typically multi-module projects have all modules versioned together, released together, and dependant on each other. This rarely makes sense in a group of spring-boot modules, which are typically of the micro-service style and which require independent evolution. So, you should question your need for a multi-module project at all.

Maven - duplicating dependency with different types/classifiers in dependency management

I'm looking at a project's POM and its dependency management section lists the same artifact 3 times - each time with different classifiers/types. What does this help you achieve?
Specifically, the dependency in question is the test module of the project. Its 3 occurrences in the POM have the following form:
default scope, default type, default classifier
default scope, test-jar type, default classifier
default scope, test-jar type, test-sources classifier
Dependency management helps organizing your dependencies in a central place. In your case, that particular artifact is going to be used in different forms in different modules:
Plain dependency
Share the test code with the module that depends on it (test dependency) - Same for 3

Maven: xpp3 versus xpp3_min

In my Java Maven project, two of my codes direct dependencies use a sub-dependency of XPP3. However, one of them has the artifact ID xpp3 while the other one has the artifact ID xpp3_min. Both are version 1.1.4c. Does anyone know the difference between the two? My project allows both to be dependencies without marking either of them as excluded due to conflict.
Home page for XPP3 project: http://www.extreme.indiana.edu/xgws/xsoap/xpp/
Maven repository reference: http://mvnrepository.com/artifact/xpp3/xpp3_min and http://mvnrepository.com/artifact/xpp3/xpp3. Notice how both projects have the same description. I don't just want to naively assume that _min is a minimal version due to its name suffix.
I've opened both archives and the xpp3_min only includes the XmlPullParser.class and XmlPullParserException.class (and MXParser.class). It doesn't include other classes like XmlPullParserFactory etc...
A popular obj <-> xml serialzer package: XStream, has both a dependency on XPP3_MIN and XMLPULL, where XMLPULL implements the XmlPullParserFactory. If it had a dependency on XPP3 it sure would have a classloading issue.

How can I efficiently declare provided scope dependencies in maven multi-module builds?

I have a maven multi-module pom which builds a war. I want to declare a provided scope dependecy on jsp-api in the parent pom. Maven docs suggest that dependencies declared as provided are not transitive, so:
Do I therefore need to go through all the sub-module poms and declare a provided dependency? There are ~40 modules in the project and it's not immediately clear which will need the dependency, so this seems like quite alot of effort to achieve not very much and I am lazy. How are you handling this situation in your projects?
--Edit--
So for others reference this was happening because the parent pom was defining all dependencies in a dependencyManagment section. I'd not come across this before but it helps with cutting down duplication of complex dependencies with excludes or other non-trivial attributes. It also overrides the inheritance mechanism. As I understand it then, a good rule of thumb is to only use it to solve a problem don't just chuck all your dependencies in there as the author of this pom had done. Perhaps a suitable maven expert could confirm this.
Even though provided scope dependencies are not transitive they may be inherited. That is to say, if you have module A with a provided scope dependency, and module B has a dependency on A, module B will not implicitly have the provided scope dependency. However, I believe that if module C has module A as a parent pom, it should inherit that dependency as normal.
You can verify this behavior yourself by running mvn help:effective-pom on one of the child poms, the effective-pom goal should give you a fully resolved view of the pom you run it on, taking into account inheritance, equivalent to what maven will actually use when it runs. If the <dependency> shows up there (as it seems to in my experiments) you should be fine specifying the dependency only in the parent pom.

Resources