Maven: how to not depend on Parent POM - maven

I have a Maven multi-module project. Something like this:
- ParentProject
- ChildA
- ChildB
- ChildC
The child projects inherit from a Parent POM (ParentProject) solely for the reason of sharing stuff like <build>, <scm> and <properties>, so as to not repeat it in all the child modules. Thus, the objective of the parent-child relationship is not related to dependencies in any way. It plays a role at build-time, not at runtime, so to speak.
The child projects's artifacts are for consumption for a wider audience, hence they'll be published into a centralized repo.
How do I "break" the relationship between from the child up to the parent seen from a perspective of a consumer of a child?
Let's say another project, ProjectX, adds a dependency on ChildA. When doing this the Maven client will attempt to not only download the POM and artifact of ChildA itself but will even try to download the POM for ParentProject. However, there's absolutely no need for that POM seen from a consumer point of view. It doesn't contain information that the consumer needs to know.
How can I break this relationship from consumer's perspective? Forcing the POM for ParentProject to be published into a repo seems pointless as nobody has any need for it there.
Perhaps there's another way that Maven will let me share things like build instructions and properties between projects without mandating that a Parent POM exists in a centralized repo ?
Or perhaps there's some way I can manipulate the POM for the Child projects which gets put into the centralized repo (removing the <parent> element as it is irrelevant).
Perhaps only me but I feel that Maven is conflating two unrelated concepts here (build-time vs consume-time) and forcing unnecessary roundtrips and unnecessary artifacts in repo. I haven't dabbled with Gradle yet but I wonder if it does it any better?

Usually, the Maven POM is both build POM and consumer POM. This is not ideal, and will probably change in future versions of Maven.
At the moment, your best option seems to be the flatten Maven plugin, which allows you to remove "unnecessary" parts of the POM before uploading it.

Related

How to deploy child module without also deploying parent module?

I have a project with a parent aggregator module and 3 children modules.
I don't know if this is a bug for me or just how Maven works, but I am currently unable to deploy one of my children modules without also deploying the respective parent. When I try to import the child module on another project of mine, Maven throws an error saying it can't resolve the parent. If I deploy both to my Nexus, it works perfectly. Do I always have to deploy both?
Yes.
You always need the parent POM as well.
When Maven need to "use" a module, it needs to resolve it.
If this module has ancestors it needs to access to every ones to resolve it.
OR you will face somethings like :
Could not resolve dependencies for project org.projectB:childA-Consumer:jar:0.1.0:
Failed to collect dependencies at org.projectA:childA:jar:0.1.0:
Failed to read artifact descriptor for org.projectA:childA:jar:0.1.0:
Could not find artifact org.projectA:parent:pom:0.1.0
Solution 1 : Deploy the parent
The common way is to deploy the parent, so this way when you consume your module maven will be able to find ancestors and so resolve your module's pom.
But lot of users seems to consider this as not so satisfying. (There are many question about that on stackoverflow ...)
Solution 2 : Parent != Aggregator
Most of the time in multi-module project, the aggregator pom is also the parent pom but this is 2 different concepts.
parent : is about sharing configuration with inheritance.
aggregator : is about building several modules at same time.
(more details about aggregator vs parent differences)
So, you can have an aggregator with several children and each child has no parent.
This way you don't have to deploy your aggregator.
Drawback you can not use inheritance to share config between modules.
Note that this is not a drawback for everyones, some consider that using inheritance and so parent is not good idea. 😅
Solution 3 : Use Maven Flatten Plugin
Currently poms contains 2 kind of information :
how to build the artifact,
how to consume it (e.g. dependencies).
Maven 5 will maybe clarify this and so you could have a different pom in your released artifacts and in your source code.
Using Maven 3, there is a plugin which aims to do that : flatten-maven-plugin
It aims to generate a pom.xml consumers oriented.
Among others, parent relationship is resolved, flattened and removed.
This way, you can use parents to share configuration between modules (with inheritance) and not deploy your aggregator and/or parents .
Drawback, you could maybe face issues with some other maven plug-in interaction ? 🤷
Some tips you need to know if you wan to use flatten-maven-plugin :
flatten cleangoal is no more useful.
how to fix url, scm url, scm connection and scm developerConnection resolution.

What is the best way to structure maven projects to make a client jar?

New to maven here...coming from the ant world
I need to create a client jar with a few files that will give my client the ability to write to my Db and make rest calls to my services.
These are mainly classes that wrap a Rest connection and db client.
Is it possible to produce this artifact as a side effect of my main maven project ?
Eg: main project produces a bundle when I run mvn package, but I'd like to produce the client jar by providing some other parameters....
What you need here is a multi-module maven project.
The structure goes like this:
-- Parent Module
----- Child 1 Module
----- Child 2 module
Here you can have all your code/files of your main app in child 1 module and put all the code/files for the client in the child 2 module.
The parent module is just an aggregator which produces an artifact of type pom. Whereas each of your child modules will produce individual jars.
You can then you the second jar in your client.
For a detailed understanding how multi-module project works, check this link.
The standard Maven way is "one project, one jar". This means that the cleanest way to achieve your goal is to set up a multi-module project where you have one module for your "normal" jar and one for your "client" jar. But there are other possibilities:
If you are talking about an ejb, you can use the maven-ejb-plugin and create a client artifact. Unfortunately, both artifacts then share the same pom (and, therefore, the same dependencies).
You can use the maven-assembly-plugin to assemble a set of files and deploy them as side artifact (same problem as in (1)).
You can use the maven-install-plugin and maven-deploy-plugin to install/deploy entirely different artifacts along with your main artifact. These artifacts need to be created before, e.g. by a custom maven plugin.

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.

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.

Maven include another pom for plugin configuration

is there a way to include another pom or information in a maven pom ?
I have several poms which are basically not related or have different parent poms. Nevertheless for packaging it is required to have a Manifest identical to all projects.
So currently I have in a pom:
<plugin>
<artifactId>maven-assembly-plugin>
<!--- .... -->
<archive>
<manifestEntries>
<build-date>....</build-date>
<build-nr>.....</build-nr>
etc etc
I would like to avoid to paste this configuration to all severall poms.
So how can I share the configuration of a plugin without inheritance ?
Thanks
One way to do this is using pluginManagement section. plugin configurations can be defined in this section in a parent pom and will be available to inherited poms to be used as is or overridden.
Here is the relevant maven documentation. In your specific case, you would need to organize your projects/poms suitably.
The only correct answer is to use inheritance. Have an inherited ancestor with this configuration in it. Since you have existing parent POMs, these must inherit from this new parent. If this isn't possible then rethink the hierarchy of your Maven projects, or else you'll have to copy and paste the same configuration into each file and add a comment indicating the section must not be modified / must be maintained consistently with [insert list of projects here].
TLDR; Inheritance is designed specifically to resolve situations such as yours. If you can't use it then don't try to hack around it - either restructure your POMs or copy and paste!

Resources