What is the difference between inheritance and submodule concepts in maven? - 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.

Related

Maven inheritance and evaluation of properties

Since system scope is said to be deprecated and dangerous, we use a local repository. The repository is in the parent folder and used by most of the submodules. Now including the repo gets messy. Providing the URL is sort of a hack.
We tried ${project.parent.basedir}/repo in the submodules, but this evaluates to nothing. We also tried to set it in the parent pom, ...
<repository>
<id>project_repo</id>
<url>file://${project.basedir}/project_repo</url>
</repository>
but maven decides to ship the url as given to the submodules which in turn evaluate the property. This lead us to the mess of just taking the relative parent dir, forcing the submodules to be subfolders of the parent pom:
<url>file://${project.basedir}/../project_repo</url>
This is problem Y. The question concerning X is, why does maven inherit before evaluation and how can I avoid this?
forcing the submodules to be subfolders of the parent pom
Regardless of other faced issue, this is actually the recommended approach in general, to have a multi-module/aggregation project (the parent) and submodules as subfolders, in order to have one central/entry-point folder (the parent) providing common configuration and governance (its pom.xml file) and modules (subfolders).
but maven decides to ship the url as given to the submodules which in turn evaluate the property.
Indeed project.basedir is evaluated as the folder containing the pom.xml against we are currently building (or sub-building, in case of a module), since the building project is the module at a given time.
From official documentation concerning project.basedir
The directory that the current project resides in.
If you want to always point to the folder from which you launched your build (that is, the aggregator/parent project in this case), you could use session.executionRootDirectory instead.
However, be careful especially if wishing to build a module directly from its directory, you may then run into troubles (path issues): you should always run it from the parent using reactor options like -pl (projects to build).
This is also a trigger for further thoughts: maintenance and readability of the project may suffer this approach. An enterprise Maven repository would then be a better solution.
Further reading on SO:
Maven variable for reactor root
Finding the root directory of a multi module maven reactor project
Update
The question concerning X is, why does maven inherit before evaluation and how can I avoid this?
Concerning your X question, here is the explanation I could find:
The answer relies in the core of a Maven build, the Maven Model Builder:
The effective model builder, with profile activation, inheritance, interpolation, ...
In particular, it performs the following steps in the following order:
phase 1
profile activation
raw model validation
model normalization
profile injection
parent resolution until super-pom
inheritance assembly
model interpolation
url normalization
Bold is mine. That is, it does so because it's made to do so by its model.

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

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.

Maven release and recomposed POM family

I'm having some issues running the Maven release plugin in my company's specific maven structure. Let me explain the concept of recomposed family I'm referring to. My projects are multimodule projects, where each module may have a different parent than its natural father.
project/
pom.xml (the natural multimodule reactor father) (I list as modules all that follows)
module1/pom.xml (my parent is NOT ../pom.xml, I'm a half sibling)
module2/pom.xml (my parent is ../pom.xml, I'm a natural child) (I have a dependency on module1)
project-war/pom.xml (my parent is NOT ../pom.xml, I'm a half sibling)
The reason we adopt this "foster parent" strategy, is that we want to activate some plugins by default for some specific "adopted siblings". For example, every WAR projects needs to define a specific maven-resource-plugin execution ID. Since we have about 80 WARs to generate, imagine the maintenance if we are to add an extra execution step to ALL WARs. This works well for development purposes, we do have valid and running SNAPSHOTs building and deploying.
Now that we want to release, the maven-release-plugin seems not to like this specific structure. In short, since module2 needs module1, but module1 has a different father, release plugin keeps module1 as a SNAPSHOT.
My question here is, has anyone manage to release a projects with recomposed family members? Is there any configuration that I need in the release plugin to enable a full release of such projects?
Violating the inheritance between modules are parent is going to give you more problems than anything else.
Your only options here are either:
fix the parent-children model so the release plugin can do its job (and then move those module activations to the children where you want it)
do the tagging, changing of versions, build+release (mvn deploy , and optionally also site-deploy) manually
After some further tests, here are my conclusions about this issue.
The recomposed family CAN be tackled by Maven on a simple condition: ALL members of the family are present in the reactor.
That would mean having a "super-reactor" that has a reference to both the project you want to release, and the parent poms that may be declared by some modules. Of course, the release plugin will then release everything in this super reactor. If you have many projects that all refer the same parent projects, you should release them in one shot.
Moreover, for the build model to be generated correctly, all relative paths must be right. In my specific case, we wanted to avoid such a thing, I guess we are back to setting a fixed folder structure.
It could be handy to exclude some projects from the release plugin, but of course that creates a potential instability.

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.

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.

Resources