Maven parent pom vs modules pom
In my opinion, to answer this question, you need to think in terms of project life cycle and version control. In other words, does the parent pom have its own life cycle i.e. can it be released separately of the other modules or not?
If the answer is yes (and this is the case of most projects that have been mentioned in the question or in comments), then the parent pom needs his own module from a VCS and from a Maven point of view and you'll end up with something like this at the VCS level:
root
|-- parent-pom
| |-- branches
| |-- tags
| `-- trunk
| `-- pom.xml
`-- projectA
|-- branches
|-- tags
`-- trunk
|-- module1
| `-- pom.xml
|-- moduleN
| `-- pom.xml
`-- pom.xml
This makes the checkout a bit painful and a common way to deal with that is to use svn:externals
. For example, add a trunks
directory:
root
|-- parent-pom
| |-- branches
| |-- tags
| `-- trunk
| `-- pom.xml
|-- projectA
| |-- branches
| |-- tags
| `-- trunk
| |-- module1
| | `-- pom.xml
| |-- moduleN
| | `-- pom.xml
| `-- pom.xml
`-- trunks
With the following externals definition:
parent-pom http://host/svn/parent-pom/trunk
projectA http://host/svn/projectA/trunk
A checkout of trunks
would then result in the following local structure (pattern #2):
root/
parent-pom/
pom.xml
projectA/
Optionally, you can even add a pom.xml
in the trunks
directory:
root
|-- parent-pom
| |-- branches
| |-- tags
| `-- trunk
| `-- pom.xml
|-- projectA
| |-- branches
| |-- tags
| `-- trunk
| |-- module1
| | `-- pom.xml
| |-- moduleN
| | `-- pom.xml
| `-- pom.xml
`-- trunks
`-- pom.xml
This pom.xml
is a kind of "fake" pom: it is never released, it doesn't contain a real version since this file is never released, it only contains a list of modules. With this file, a checkout would result in this structure (pattern #3):
root/
parent-pom/
pom.xml
projectA/
pom.xml
This "hack" allows to launch of a reactor build from the root after a checkout and make things even more handy. Actually, this is how I like to setup maven projects and a VCS repository for large builds: it just works, it scales well, it gives all the flexibility you may need.
If the answer is no (back to the initial question), then I think you can live with pattern #1 (do the simplest thing that could possibly work).
Now, about the bonus questions:
- Where is the best place to define the various shared configuration as in source control, deployment directories, common plugins etc. (I'm assuming the parent but I've often been bitten by this and they've ended up in each project rather than a common one).
Honestly, I don't know how to not give a general answer here (like "use the level at which you think it makes sense to mutualize things"). And anyway, child poms can always override inherited settings.
- How do the maven-release plugin, hudson and nexus deal with how you set up your multi-projects (possibly a giant question, it's more if anyone has been caught out when by how a multi-project build has been set up)?
The setup I use works well, nothing particular to mention.
Actually, I wonder how the maven-release-plugin deals with pattern #1 (especially with the <parent>
section since you can't have SNAPSHOT dependencies at release time). This sounds like a chicken or egg problem but I just can't remember if it works and was too lazy to test it.
Differences between a multi-module project and a parent project
Why this two-way definition?
It is not mandatory. It is a design choice.
Why not define just in the parent?
If you define them only in the modules
tag of the parent pom, you will only use the reactor/aggregation feature of Maven.
1) Aggregation (<modules>
declaration in the super aggregator project) provides mainly these features:
- Collects all the available modules to build
- Sorts the projects into the correct build order
- Builds the selected projects in order
Aggregation module is enabled by declaring the modules to aggregate in the parent pom:
<modules>
<module>my-child</module>
<module>my-other-child</module>
</modules>
But aggregation doesn't provide inheritance.
2) Project inheritance (<parent>
declaration in the child modules) provides the inheritance of multiple things from the parent declaration to the child module :
From the actual documentation, most elements from the parent POM are inherited by its children:
groupId
version
description
url
inceptionYear
organization
licenses
developers
contributors
mailingLists
scm
issueManagement
ciManagement
properties
dependencyManagement
dependencies
repositories
pluginRepositories
build
plugin executions with matching ids
plugin configuration
reporting
profiles
Inheritance is enabled by declaring the parent artifact in the child poms:
<parent>
<groupId>my-group</groupId>
<artifactId>my-parent</artifactId>
<version>1.0.0</version>
</parent>
<!-- You can note that groupId and version are not filled for the current project.
These are optional as inherited from the parent -->
<artifactId>my-artifact</artifactId>
In fact, you can use project inheritance, project composition, none of them or both.
It is really a design choice that should be done according to the relation between the projects and their requirements.
You may refer to this interesting point on the Maven documentation about these two features:
Project Inheritance vs Project Aggregation
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.But of course, you can have both Project Inheritance and Project
Aggregation. Meaning, you can have your modules specify a parent
project, and at the same time, have that parent project specify those
Maven projects as its modules.
To illustrate using an example.
Here is a multi-module project's parent pom.xml.
<!-- PARENT POM -->
<groupId>com.example</groupId>
<artifactId>parent-demo</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>child-module</module>
</modules>
And here is the Child Pom.
<!-- CHILD POM -->
<parent>
<groupId>com.example</groupId>
<artifactId>parent-demo</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>chile-module</artifactId>
Here, child-module
inherits parent-demo
, but parent-demo
does not use any inheritance.
And if you want, your parent-demo
to also use inheritance, you can configure your parent-demo
like below.
<!-- PARENT POM -->
<parent>
<groupId>com.example</groupId>
<artifactId>parent-deps</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../parent-deps</relativePath>
</parent>
<artifactId>parent-demo</artifactId>
<packaging>pom</packaging>
<modules>
<module>child-module</module>
</modules>
And now, your parent-demo
is also inheriting configurations from parent-deps
which are cascaded down to child-module
as well (unless ofcourse parent-demo
decides to override them).
what is the difference between parent/parentanddependencydependency in maven?
<parent>
a superset of <dependencies>
<parent>
and <dependencies>
elements are two distinct things but it exists all the same an important relation between them.
Simply said the parent
defines the parent pom of the current pom and dependencies
defines the actual dependencies of the current pom.
The parent pom can define dependencies
but also many other things inherited by the children Maven project (and particularly the dependencyManagement
element and the build
element that allow to configure many things) can so be considered in a some way as a superset of the dependencies
element.
Here is the list of elements inherited from the parent pom :
groupId
version
description
url
inceptionYear
organization
licenses
developers
contributors
mailingLists
scm
issueManagement
ciManagement
properties
dependencyManagement
dependencies
repositories
pluginRepositories
build
plugin executions with matching ids
plugin configuration
etc.
reporting
profiles
As use dependencies
and as use <parent>
?
We can use only the first, only the second or both.
It depends really on the way which the Maven projects are designed.
Trying to enumerate all possible configurations would be long and not necessary very helpful.
So I think that you should really retain that parent
is much more structuring as dependencies
as it defines both more things for the children projects but it also allow not to repeat the actual configuration that you want to define in a set of projects.
So you should favor parent
as you want to make inherit some child Maven projects an overall configuration and not only a list of dependencies.
Your example is perfect to illustrate the consequences on the client projects from using <parent>
or dependencies
as alternative.
1) With parent inheriting
Here the project inherits from the spring-boot-starter-parent
pom :
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
</parent>
As a consequence, the project will inherit any things defined in dependencies
and dependencyManagement
but it will also inherit from the <build>
element defined in the super pom.
For example you would have the Maven compiler plugin configured out of the box with Java 8 and UTF-8 (that you can of course redefined in your child project) :
<properties>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<resource.delimiter>@</resource.delimiter>
<maven.compiler.source>${java.version}</maven.compiler.source>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.target>${java.version}</maven.compiler.target>
</properties>
Additionally, some other plugins potential useful by a Spring Boot project will also be defined in the super pom and be inherited by your project such as :
<pluginManagement>
<plugins>
...
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>${start-class}</mainClass>
</configuration>
</plugin>
...
</plugins>
</pluginManagement>
Note that a parent pom may define dependencies
, directly inherited by the child projects but not necessary.
For example the spring-boot-starter-parent
doesn't define any dependency
directly inherited by child projects but instead of define dependency
in <dependencyManagement><dependencies>
.
It means that children of this parent pom may use the dependencies but they have to explicitly state that in dependencies
.
For example :
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
Note that the version is not valued as inherited.
2) Without parent inheriting
You will have to define all required dependencies by your Spring Boot application in or more straightly use the spring-boot-dependencies
dependency in dependencyManagement
with a import
scope to have a way to declare them thanks to the dependency management feature :
<dependencyManagement>
<dependencies>
<dependency>
<!-- Import dependency management from Spring Boot -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.5.2.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
But in any cases you will never inherit from the plugins
configured out of the box by the parent as you don't have parent.
So you should declare them explicitly in the pom.xml of your project.
For example to define the compiler version, used encoding and configure the build to repackage the built component(to make it standalone executable), you will will have to specify more things :
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<springboot.version>1.5.2.RELEASE</springboot.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${springboot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${springboot.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>myClass</mainClass>
</configuration>
</plugin>
<plugins>
</build>
Related Topics
Autocomplete with Java , Redis, Elastic Search , Mongo
When to Use Entitymanager.Find() VS Entitymanager.Getreference() with JPA
Increasing the Jvm Maximum Heap Size for Memory Intensive Applications
Unit Testing a Class with a Java 8 Clock
Hiding Instance Variables of a Class
What Is the Significance of Load Factor in Hashmap
Isn't the Size of Character in Java 2 Bytes
Creating a Bundle Jar with Ant
Java - Does Null Variable Require Space in Memory
How to Check That a String Is Parseable to a Double
Layering Multiple Glasspane's in a Root Container
How to Get the Caller Class in Java
Write a File in Hdfs with Java
The Connection Between 'System.Out.Println()' and 'Tostring()' in Java
Why There Is No Concurrenthashset Against Concurrenthashmap
Java Generate Random Number Between Two Given Values
Communication Between Two Separate Java Desktop Applications