How does Maven's Aggregation Model comply with its Dependency Mechanism? - maven

My question is relatively simple. I do have a project that has a typical parent pom with a dependency management and a module with a pom that "normaly" inherits those dependencies.
If I explicitly name the parent inside the inherited pom, then the project builds successfully, but if I omit the parent information then the project fails to build.
One would expect maven to be able to build this project normally since the aggregation pom lists all the modules along with the dependency management.
Why is that not the case?

Because you are mixing inheritance with aggregation.
In Maven, inheritance means declaring a parent POM for this POM (with the <parent> tag element). By default, each POM inherits from the Super POM. This inheritance allows to factor out common dependencies inside the parent (like plugins version or dependency management).
On the other hand, aggregation is a synonym for a multi-module project. This means that an aggregator project declares sub-modules (with the <module> tag element).
Even if it's not commonly used, you could have a project that aggregates sub-modules for which their parent is not this project. It is very common to see parent projects that are also aggregator project but it's not a necessity. So the build fails in your case because you reached the situation of an aggregator project that is not a parent project anymore so the sub-modules do not inherit from its configuration.
Quoting from the Maven docs:
A POM project may be inherited from - but does not necessarily have - any modules that it aggregates. Conversely, a POM project may aggregate projects that do not inherit from it.
Further reading:
The Maven book: Multi-module vs. Inheritance (selected quote):
There is a difference between inheriting from a parent project and being managed by a multimodule project. A parent project is one that passes its values to its children. A multimodule project simply manages a group of other subprojects or modules. The multimodule relationship is defined from the topmost level downwards. When setting up a multimodule project, you are simply telling a project that its build should include the specified modules. Multimodule builds are to be used to group modules together in a single build. The parent-child relationship is defined from the leaf node upwards. The parent-child relationship deals more with the definition of a particular project. When you associate a child with its parent, you are telling Maven that a project’s POM is derived from another.
Maven documentaton: Project Inheritance vs Project Aggregation (selected quote):
If you have several Maven projects, and they all have similar configurations, you can refactor your projects by pulling out those similar configurations and making a parent project. Thus, all you have to do is to let your Maven projects inherit that parent project, and those configurations would then be applied to all of them.
And if you have a group of projects that are built or processed together, you can create a parent project and have that parent project declare those projects as its modules. By doing so, you'd only have to build the parent and the rest will follow.

Related

Is it possible to see the actual pom.xml executed, including parent dependencies/plugins?

I need to extract a project from a repository which uses several layers of parent projects. Every parent project adds some dependency or plugins or properties. This is becoming a nightmare as I'm not able to build any more the project, once I've manually added pieces from parent projects.
Is there a way to create a list of all dependencies/plugins/properties which are linked by a single pom.xml so that I can build a portable, single Maven project?
Thanks
You can create the effective pom (https://maven.apache.org/plugins/maven-help-plugin/effective-pom-mojo.html) that is a kind of merge with all parent POMs.
This is useful to understand the complete list and configuration of plugins.
Whether this helps you to build a "portable" Maven project, I don't know. Without the appropriate Maven repositories with all the plugins, dependencies and so on, Maven will not build.
Base concept of Maven is CoC (Convention over Configuration). Maven has a SuperPOM and all model is inherited from that. SuperPOM is located in maven-model-builder jar. Here is the source https://maven.apache.org/ref/3.6.2/maven-model-builder/super-pom.html
Each Maven goal is using a merged model called effective pom. The help plugin has effective-pom goal which displays the full model including parent model(s) and SuperPOM.
So the answer is just run: mvn help:effective-pom command to see actual model.

maven parent pom with the differnt child versions vs parent POM with the same child versions

can any one let me know the exact difference between the parent pom with the different child versions and parent pom with same version in the child modules.
i was in confusion, is there any major tactic in this when we are going to multiple versions at module level.
1) let say parent module 1.0 and child modules are 2.0,3.o,.....
is there any problem?
In my experience there are two cases when using parent POMs.
We just want to inherit basic configuration (plugin management, some basic libraries that are used from many projects (e.g. logging) etc).
We want to aggregate a set of modules as a multi-module project in order to build, test, release all the modules at once.
In the first case, it is reasonable that the parent POM may not be in the same version as its "children".
In the seconds case, we definitely want the parent POM version to be in synch with the version of its modules.

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.

What is the difference between inheritance and submodule concepts in maven?

What is the difference between inheritance and submodule concepts in maven? Lets say I have a project A whose parent is project B ? In that case is A a submodule of B or is it something entirely different ?
Inheritance concept in maven is very similar to inheritance in OOP. Usually you inherit (include <parent> section in your pom.xml) when you want to reuse other project's settings, like dependencies, repositories, build plugins etc.
Submodules concept is different. It addresses a very common case in software development when your project consists of some number of smaller projects, each serving its own goal. In maven terms it is accomplished through <modules> section in pom.xml. When you execute maven goal being in the root of the main project, this goal gets propagated to all of the subprojects and executed there as well.
In most of the cases, though, both of these concepts are utilized together. You have main pom.xml file that defines common dependencies, build lifecycle, settings, properties, repositories etc. and set of modules. Each of modules inherits configuration from the main pom.xml and might add something specific.

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.

Resources