The situation is, I have two Maven multimodule projects with the same structure:
Parent
- Module 1
- Module 2
When I build project 1, I see that parent is built first (order is parent->module1->module2). However for project 2, parent is built at last (order is module1->module2->parent). Why are the two projects have different build orders? Furthermore, how can I manually control the build order?
Update 1:
Both parent projects are simple POM projects without source code, so I can't explain the build order as per the dependency graph.
Update 2:
The parent POMs are the same except the GAV and child module names:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>parent-group-id</groupId>
<artifactId>parent-artifact-id</artifactId>
<version>parent-version</version>
<packaging>pom</packaging>
<name>parent-name</name>
<modules>
<module>module-1</module>
<module>module-2</module>
</modules>
</project>
The build order is determined by the Maven reactor which is a mechanism that automatically ensures correct build order for multimodule builds by sorting the projects.
See the official documentation for how it works.
It says:
The following relationships are honoured when sorting projects:
a project dependency on another module in the build
a plugin declaration where the plugin is another modules in the build
a plugin dependency on another module in the build
a build extension declaration on another module in the build
the order declared in the element (if no other rule applies)
You can't manually control the build order. If you want to change the order you have to make changes to your project that influence the reactor sort order.
At a high level, the build order is based on a topological sort of the module dependency graph.
EDIT: Question for you. I understand that project 1 contains two modules and so does project 2. But do the modules in project 2 explicitly declare the "parent" pom as a parent? I'm thinking that perhaps your project 1 modules explicitly declare the parent pom, and the project 2 modules don't. Which would mean that the project 2 "parent" isn't really a parent at all and therefore doesn't have to be built before the modules. That's my guess anyway.
I've been having this issue lately with CentOS 7. I updated Maven to 3.5.3 from 3.0.5 and the problem has been solved. If anyone have this issue as well you can try doing that first.
Summary
Why?
Maven is using <module> declarations to determine the list of modules to include in the current run. Maven is using <parent> declaration to generate effective POM for each included module, which is then used to execute the build for that module.
In Project 1, each of module1 and module2 specify parent module in <parent> section.
In Project 2, neither module1 nor module2 specify parent module in <parent> section.
How can I manually control the build order?
By changing dependencies between modules, including <parent>, <dependencies>, plugin dependencies, etc. as described in the official documentation.
Please check also Introduction to the POM for the discussion on aggregation and inheritance.
Details
There are 4 possible scenarios of module relationships in Maven in terms of aggregation (<module> declaration) and inheritance (<parent> declaration).
Let's assume a module A with packaging pom and a module B (packaging does not matter). The module A could either be a parent or an aggregator. The module B could either reference A as parent or not.
Case 1:
Neither A nor B reference each other - the modules are independent.
The Maven can not control build order, each module gets built independently, with manual build order control.
Case 2:
The module A includes the module B in <modules>. The module B does not declare A as parent. The module A is an aggregator for the module B in this case.
Maven invocation mvn -f A/pom.xml will first build B, and then A.
Maven invocation mvn -f B/pom.xml will build B only.
Case 3:
The module A includes the module B in <modules>. The module B declares A as parent. The module A is both the parent and the aggregator (reactor) for the module B in this case.
Maven invocation mvn -f A/pom.xml will first build A, and then B.
Maven invocation mvn -f B/pom.xml will build B only, but will use the POM of A to generate effective POM of B by resolving it either from the local repository or by following /project/parent/relativePath.
Case 4:
The module A does not include the module B in <modules>. The module B declares A as parent. The module A is the parent for the module B in this case.
Maven invocation mvn -f A/pom.xml will build A only.
Maven invocation mvn -f B/pom.xml will build B only, but will use the POM of A to generate effective POM of B by resolving it either from the local repository or by following /project/parent/relativePath.
Related
Let's say I have a maven project which has some maven modules inside.
My main module depends on the other modules, so when I compile the main module they should be compiled together.
The question is, how to add these modules as dependencies to the main module?
I know if I have a custom lib that I want to use with maven, let's say a utilities project, I have to compile the jar of the project, do a mvn install:install-file on it to install it on the local repository and then add it to the pom.xml.
Do I have to do this with all my modules and add the dependency to the pom.xml on my main module? Because if it should be done like this, there will be a lot of work to do when changing code on the other modules.
What is the best practice to use avoid the trouble of compiling/installing the modules to local repository?
The question is, how to add these modules as dependencies to the main module?
The same way you add any other dependency to your maven project. By adding group id, artifact id and version to <dependency> element
Do I have to do this with all my modules and add the dependency to the pom.xml on my main module?
If your main module depends on some module A then only the pom of the main module should contain dependency declaration towards module A. You do that for all the dependencies of your module.
I don't know what you mean by "a lot of work when changing the code on other modules". Maven has nothing to do with code changes, it just builds the projects whatever they look like at the given moment...
What is the best practice to use avoid the trouble of compiling/installing the modules to local repository?
Any project that you invoke mvn install on gets built and it's jar copied to local repository. That's all you need to do to get the jar into the repo. This will also put all the dependent jars, if available, into the local repo.
As for best practices for multi module projects:
If your parent project (the one that has modules inside) has <modules> section that lists the modules of your application, and modules are in subdirectories of your parent project, then you simply mvn install (or whatever you want to do) the parent project and that will cause all the modules to be built in order defined by declared dependencies between them. That means that if your main module has dependency on module A, then module A will be built before the main module. This way you can build and install all your modules with one command. On the other hand this approach makes more tight coupling between modules which is not desired in some cases, so it depends on your use case whether it is a good approach or not.
I have 3 projects, A->B->C in that dependency order. Currently everytime I make a change to B or C I have to go to the directory and do a mvn clean install in order to install it into the local repository. It is troublesome if I have to do this every time the projects updates.
How can I do it such that every time I do a mvn clean package on A, it will automatically build and install my dependent projects B and C into the local repository?
Create a parent project for all your projects A,B,C and then add all your child project on the parent pom.xml file something like this
<modules>
<module>A</module>
<module>B</module>
<module>C</module>
</modules>
Its called maven multi module project mentioned by #khmarbaise
Here are some example for this
How do I create a multi-module project in Eclipse?
Maven Multi module tutorial
Guide to Working with Multiple Modules
By use of multi module project you will get plenty of benefits like
Anytime you can add any new project with all of the current project
Separation of project is good for code cleanup
You can build Single project or You can build all project in one go.
Duplicacy of jar can be easily ignore .
Maven take care of the build order for you.
One single Jenkins job to build everything.
Plenty of other benefits.But remember if there will some pros then cons also there,its totally now what you want to use .
You can follow the solution I provided to the question Maven 2 Projects, since it is the pattern I usually use when building project with a certain complexity.
Summarizing you would have to create a main Maven project which has three submodules, say master, platform and parent.
The main project has simply the order in which the other projects will be evaluated by Maven
The master pom contains the list of project to be built and their order (aka Reactor order)
The platform pom contains all information about your platform, like JDK version, maven plugin versions, encoding and so on.
The parent pom has the platform pom as a parent and contains all global GAV information about the dependencies you are going to use in your project (Spring, CXF, junit, log4j etc.)
Any maven experts out there? I inherited a huge maven project and am trying to get it to compile. Not getting very far. I go to the highest level pom.xml I can find, located in trunk directory, one level down from the main project. Then I issue command "mvn validate". Get the following error:
[INFO] Scanning for projects...
Downloading: http://repo1.maven.org/maven2/com/mycompany/neto/vsd/vsd-superpom/1.1.0/vsd-superpom-1.1.0.pom
[INFO] Unable to find resource 'com.mycompany.neto.vsd:vsd-superpom:pom:1.1.0' in repository central (http://repo1.maven.org/maven2)
I noticed a vsd-superpom folder at the same level as the main project so I'm guessing the main project needs to point to it somewhere? Looking at the pom.xml I see
<parent>
<groupId>com.mycompany.neto.vsd</groupId>
<artifactId>vsd-superpom</artifactId>
<version>1.1.0</version>
</parent>
Where do I put the vsd-superpom folder so that it will be found? I don't understand why it tries to download it. I don't see anything in pom.xml that tells it to do that.
Apache Maven has a two level strategy to resolve and distribute files, which we call artifacts. The first level is called the local repository, which is the artifact cache on your system, by default located at ${user.home}/.m2/repository. When executing Maven, it'll first look in this local cache for artifacts. If the artifact cannot be found here, Maven will access the remote repositories to find the artifact. Once found it will be stored into the local repository, so it's be available for current and future usage.
see Apache Maven Install Plugin Documentation
So if your super pom is independent of the rest of the project you can simply invoke mvn install from the super pom folder so that it will be placed into your local repository. That will solve your problem.
Usually the top-level project pom defines the project dependencies and it should be enough to invoke mvn verify | compile | ...
If the top-level pom depends on the super pom that you have to install the super pom first (or define a pom that contains the submodules super pom and rest of the project)
Common project structure what I have seen (and used) is:
foo-parent
pom.xml - parent POM for my modules with parent ../pom.xml
foo-module
pom.xml - module POM with parent ../foo-parent/pom.xml
...other modules...
pom.xml - multimodule POM without a parent
Now if I want to build foo-module I need to be in the top-level folder and run:
mvn -pl foo-module -am package
In other words you are always building the multi-module project. However you can specify that you are interested only in some submodules (-pl) and their dependencies (-am).
This question already has answers here:
Build order of Maven multimodule project?
(4 answers)
Closed 6 years ago.
I have a Maven parent project which has multiple child/modules...I have the following pom.xml for the main/parent;
<modules>
<module>Main-Ear</module>
<module>Sub-Web</module>
<module>Sub-Ui</module>
<module>Sub-Services</module>
<module>Sub-SSO-Login</module>
</modules>
However, I find the actual build order to be different...
After build, the actual order looks like;
Main
Sub-Services
Sub-SSO-Login
Sub-UI
Sub-Web
Main-Ear
Where exactly does Maven take the build order from in this case?
You can't manually control the build order:
From Maven project documentation (Guide to Working with Multiple Modules):
Reactor Sorting
Because modules within a multi-module build can depend on each other,
it is important that The reactor sorts all the projects in a way that
guarantees any project is built before it is required.
The following relationships are honoured when sorting projects:
a project dependency on another module in the build
a plugin declaration where the plugin is another modules in the build
a plugin dependency on another module in the build
a build extension declaration on another module in the build the order declared in the element (if no other rule applies)
Note that only "instantiated" references are used -
dependencyManagement and pluginManagement elements will not cause a
change to the reactor sort order
Maven not taken the module building order from what we define in the main pom.xml. Maven decide the order by considering module dependencies with each other modules.
In your case definitely Main-Ear should build last.
Let's consider following example.
I have module A, B and C. Module A has dependency from module C and B while module C has dependency from module B. Then maven building order will be
B
C
A
Situation with inheritance in maven. I want create hierarchy of projects.
Something like main POM <- module1 <- module2.
I trying in my main POM to define module1 with <module> module1</module>. In module2 i define parent POM with <parent> tag. But after comand "mvn clean package" in main project folder, there is no jar created in the module2 directory.
can someone explain me what i have to do.
Thanks.
You can install the child project into your local repository and include it in the list of dependencies in your parent project. If you're not making changes often to the child project then I've found the install+refresh is quicker overall than having your IDE constantly scanning multiple projects to resolve dependencies.
module1 must have POM packaging
And there you have your answer. Only modules with POM packaging can contain other modules.