Advise on setting up maven for multiple projects - java

I was looking at some open source projects and noticed they have a setup like:
/app1/pom.xml
/app1/app1-mod1/pom.xml
/app1/app1-mod2/pom.xml
/app1/app1-mod3/pom.xml
So there is a master pom, and then all the modules have pom.xml also.
So in my situation I have the following:
1. spring mvc application
2. spring mvc application
3. shared model/db layer
So I guess I should be following the multiple pom.xml setup?
If yes, how will I get #3 to build before #2 and #1.
Should I be dropping down to ant to perform the actual build?
Any tutorials that you guys know of to walk me through this process?
I'm coding in IntelliJ.

The Maven reactor will build the modules in an appropriate order, you can tell it what you think the best way is by sorting them how you want.
I have a similar project setup like this:
<artifactId>root</artifactId>
<packaging>pom</packaging>
<name>Root</name>
<modules>
<module>event</module>
<module>admin</module>
<module>public</module>
</modules>
This is then used as a parent by the other modules. The event library is used in both the admin and public webapp modules. In the webapp modules define something like this:
<dependencies>
<!-- Events -->
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>event</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
A mvn install from the root works beautifully.

Maven will calculated the dependencies by itself it you setup your POMs so that
module #1 and #2 both depend on #3 maven will build #3 first without any additional configuration required.
The layout you use (multi module) is also required for the release plugin.
See also A Multi-module Project

Related

How to avoid DuplicateProjectException exception

Hy,
I have a multi-module maven project. I use to create these projects with Talend studion. I try to create a CI/CD build flow in MS Azure devops based on the Talend studion generated code. The generated maven poms are look like:
Parent pom:
<Modules>
<Module>Project A<Module>
<Module>Project B<Module>
</Modules>
Module A pom:
// no reference to other module
Module B pom:
<Modules>
<Module>Project A<Module>
<Module>pom-control-bundle.xml<Module>
<Module>pom-feature.xml<Module>
</Modules>
When I try to queue with MS Azure devops, I encounter this error message:
DuplicateProjectException : Project A is duplicated in the reactor #
Any idea, what should I configure to solve this problem?
I just recognised no need to build the whole project but the subproject. In Talend, you create jobs, services, route, and they are separated java projects. If they will publish somewhere you need to upload the job, service, route, not the whole project. So, I need to run the build flow on the job, service, route. So I need to point on the job's -also service, route, etc...- pom.xml not the parent project's pom.xml.
So you can avoid this error above, if you build the modules separate.

How to avoid Java dependency hell when using Maven multi-module projects

I have been battling dependencies on a Java Maven multi-module project for a couple of days.
With too little oversight developers managed to create a situation where modules each can be compiled on their own but not as a single whole together. This results in all kinds of errors. Classes that cannot be found, casting errors etc etc. The cause of these problems seems impossible to determine.
My suspicion is that Maven puts conflicting dependencies on the class path. I think we made a mess of the Maven dependencies but regardless I don't understand how Maven can be such a poor performing framework for multi-module projects.
Now I can understand that Maven tries to do very smart useful things when compiling multiple modules as a whole but shouldn't there be an option in Maven to just configure a module to be isolated from other modules? Is there such an option? To avoid this dependency hell?
Or is the Maven best practice to create other scripts, bash scripts for example to be able to compile multiple modules in isolation, with one command?
But that is also poort workaround some tools for example SonarQube require ability to run Maven on the whole code base in order to create a single project in SonarQube.
This results in all kinds of errors. Classes that cannot be found, casting errors etc etc. The cause of these problems seems impossible to determine.
Could you post the error messages? it would make analyzing your issues easier. This may be caused by dependency conflicts, but it is hard to say without more information.
Now I can understand that Maven tries to do very smart useful things when compiling multiple modules as a whole but shouldn't there be an option in Maven to just configure a module to be isolated from other modules? Is there such an option? To avoid this dependency hell?
I do not get this. If two modules do not depend on each other, their builds will be independent. If one module depends on another module and its build fails because of version conflicts, this build will fail regardless of whether it is built together with the other modules or in isolation.
Or is the Maven best practice to create other scripts, bash scripts for example to be able to compile multiple modules in isolation, with one command?
Maven follows the philosophy "convention over configuration", meaning the more you follow the convention, the less configuration you will have and the less maintenance work. Creating all kinds of scripts goes against this philosophy and is not Maven's best practice.
To manage dependency conflicts in a multi module project, you would typically have a parent module with a pom.xml that looks like
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>...</groupId>
<artifactId>...</artifactId>
<version>...</version>
<packaging>pom</packaging>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>6.0</version>
<scope>provided</scope>
</dependency>
...
</dependencies>
</dependencyManagement>
<modules>
...
</modules>
</project>
In the dependendencyManagement element you define the version of libraries used. This way you force each module to use the same version of libraries.
For Maven, I often recommend the Java EE NetBeans IDE, because among other things it has a good visualisation tool for dependencies, which is useful in detecting and removing version conflicts. (I am not aware of a similar tool in Eclipse or IntelliJ). If you open a Maven project in NetBeans, click on the pom.xml (in the Projects window) and then select Graph > Show Graph.
I use this tool for 2 things:
remove the transitive dependencies in Maven, otherwise you have to manage more dependencies than required. To remove transitive dependencies, right click in the graph and select the Hierarchical layout. Every dependency that is not on the first line is a transitive dependency and can be removed from the pom.xml.
identifying conflicts between transitive dependencies. (Conflicts are coloured red in the graph.) I resolve these conflicts by explicitly setting the version for the dependencies in the dependencyManagement element in the root pom.xml

Update version of Maven modules in one place only

I have a Maven project with 2 modules. I want the modules to inherit the version of that project, without defining it as a parent in the POM file of any submodules (the reason behind that is that the modules already have parents). What would be the best way to achieve that?
Importing the version from a properties file doesn't work because maven expects a constant value as a project version, not an expression. Maven plugins such as the version maven plugin or the maven release plugin are not solutions to my problem because I need something that would work in an IDE (I have to use Eclipse for packaging the projects, not my call).
Edit
To clarify things (apologies if my original post was not clear enough)
Main Project POM file
...
<groupId>org.mygroup</groupId>
<artifactId>parentproject</artifactId>
<version>1.1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>module1</module>
<module>module2</module>
</modules>
...
Module POM file example
...
<groupId>org.mygroup</groupId>
<artifactId>module1</artifactId>
<version>1.1.0-SNAPSHOT</version>
<packaging>war</packaging>
<parent>
<!-- Some parent that's NOT the main project, e.g. Spring Boot -->
</parent>
...
What I want is a solution that would allow me to set the version only ONCE (e.g. in the main project POM file) and having every module of that project to "inherit" that version.
You should probably set the parent back to your actual parent project. Version numbers between modules can be simultanuously updated using mvn versions:set. If you need the version number for cross-module dependencies, use ${project.version}. If you want to embed another Maven configuration file for its dependencies, consider using a Bill-of-material (BOM): https://stackoverflow.com/a/14876651 . Hope things brings you to your answer!
I really can't think of any Maven facility that fit 100% your necessities. Event if you could set the parentproject as an actual parent on each submodule, you'd need to specify its version in the parent declaration, so...
But I think of a trick to do the job through an authomatism, so that every time the parent version is changed, it will be automatically propagated to each submodule. It can be done like this:
Program a plugin in the parent project that writes the version id on each of its modules' pom files (for example, through an XSL transformation with the xml-maven-plugin).
Then, link this plugin to the package phase, so that every time the parent is build, the versions gets propagated to the submodules.
You only will have to refresh the submodules projects in Eclipse to make Eclipse be aware of the changes.
But if you don't want to refresh manually, there is still another alternative - fully based on Eclipse:
Make an Ant script to perform the copy-version-to-all-module-poms task. And, instead of calling it from a Maven phase, program an Eclipse builder to call it and, within this builder, program also a refresh of the specific modules. So, every time you execute a build of your project, it will copy its version to the submodules and make Eclipse be aware of this change.

One maven project using different dependencies in build phase

I've got a project, name it project1 and this project contains one pom.xml. Now, what I want to achieve is, that I want to specify two different "Profiles" in Eclipse when I run a maven build on the project and then each of the two profiles should use it's own dependencies. For example in build phase "build_project1_dependency1" it should use the following dependency:
<dependency>
<groupId>com.example</groupId>
<artifactId>ProjectX</artifactId>
<version>1.0.11</version>
</dependency>
and in the second build phase profile called "build_project1_dependency2" it should use the following dependency instead of the first one:
<dependency>
<groupId>com.example</groupId>
<artifactId>ProjectX</artifactId>
<version>1.0.12</version>
</dependency>
I canno't commet because i'm new here so i'll copy the link.
(i have no idea if it is right or not)
Maven assembly : add different version of the same artifact
or you can try this:
Copy two versions of same jar using maven
just search :)

Get started with maven

I have experience in Ant, how to get started with maven. Any advantage with maven over ant?
There's a quite large difference, where ant forces you to create your own targets you will get a default set of targets for maven, e.g., clean, install, package etc without scripting them.
Maven promotes that you use a common directory structure for java classes, resources etc. If you do, maven is just on xml file where you specify some project metadata such as name, package and most importantly depenencies. It provides similar dependency lookup to what ivy does for ant.
Based on the standard maven promotes, it becomes very easy for developers to approach and build your projects. With an IDE such as Netbeans it's enough to select open project, and then hit the install button to compile and install the project in your local repository.
I recommend working with maven the maven way. Doing things differently will often cause more pain than it's worth. Maven offers a plugin structure where you can perform various tasks, such as invoke the ant-library should you need to. If you're actively working with multiple projects (and want project switching to be as easy as possible) maven is a huge leap forward, especially if combined with repository server such as Nexus or Archiva.
To get started
Either you can generate your project structure using the archetype goal of maven, or you could do it the way I do by copy-pasing an empty template project every time. Then you need the maven binary and the project definition file pom.xml which I typically also copy paste between projects.
A sample is included below. With this sample you'll get the external library log4j, and you automatically get all nececcities to build and package your own project (in this case to a jar file).
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.company</groupId>
<artifactId>projectname</artifactId>
<packaging>jar</packaging>
<version>0.1.0-SNAPSHOT</version>
<name>${project.artifactId}</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
<!-- add more dependencies here ... -->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
Around two weeks ago, I was in the same situation. In my opinion, Maven is a lot more powerful as compared to Ant.
It has a generate command which makes it very easy to start new projects of various kinds (artifacts) and will also build a standard directory structure along with the pom.xml file,
thereby taking care of a lot of things that are needed to be written in the build.xml file of Ant.
Managing dependencies is also a lot better. Maven will download dependencies from repos and will store them in a central repo on your system. If a dependency is already present in the local repository, it will take it from there instead of downloading it again.
I use eclipse and maven has a command (mvn eclipse:eclipse) which creates the .classpath file in the project directory. So no need to add the libraries again in eclipse.
The Getting started guide on the maven website is a good resource and covers quite a lot of stuff -
In comparison to Ant what Maven does well is dependency management and standardisation of the build lifecycle.
As for learning a bit more about it, the Maven documentation is pretty readable and thorough.
I'd start by looking at the introductory piece that explains some of the core principles about the difference between Maven and other build tools.
http://maven.apache.org/what-is-maven.html
Then downlod and install maven, open your terminal and type...
mvn archetype:generate
Select all defaults and you'll end up with a simple build-able project with one runnable class and a matching test file. Use that as a test project to familiarise yourself with the build lifecycle and dependency resolution process.

Categories

Resources