Module dependency vs artifactory - java

We have maven aggregated pom project as below
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.abc</groupId>
<artifactId>project</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>module-1</module>
<module>module-2</module>
<module>module-n</module>
</modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.xyz<groupId>
<artifactId>framework</artifactId>
<version>1.1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.xyz</groupId>
<artifactId>dao</artifactId>
<version>1.1.1-SNAPSHOT</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
module-2 has dependency of module-1
AND module-n has dependency of module-1 & module-2.
The maven reactor can resolve all inter-module dependency (build order is module-1, module-2, module-n).
Some shared components from com.xyz is also used by the modules (e.g. framework). They are retrieved from the remote artifactory server, while the inter-module dependency artifacts (e.g. module-1.jar) are retrieved locally during maven build.
My question is what is the best way to associate the dependencies. By module or by the artifacts stored in artifactory server? This example has both usage. I could not figure out under which circumstance we should
1) group all inter-dependent modules under the same parent pom OR
2) always pull the depending artifacts from remote artifactory repo and let each of the module built independently
Any pros and cons? Sorry for my poor English. I hope my question is clear. Thank you!

The rule of thumb is:
Do you always build the jars at the same time? Then they should form a multi-module project.

Related

Spring boot multi module maven projects without repository

I have multiple spring boot projects, every project is independent and has its own CICD pipeline.
These projects need some common classes, I have created a separate project with common classes.
Parent
pom.xml (with packaging)
lib-project
pom.xml
project-1
pom.xml
project-2
pom.xml
I can build project easily from the parent directory, it builds all the projects
parent$ mvn clean package
it generates all the jar files and put them in their respective target folder of projects
My problem is I can't initiate this at the parent level, this has to be initiated from within each project from its own pipeline.
and
I cannot use any local or remote repository, to put the dependent jar in m2 using mvn clean install and then refer to it as dependency
I want to build it from the relavent project directory
parent/project-1$ mvn clean package
it shows following error:
Could not resolve dependencies for project com.test.multiple:project-1:jar:0.0.1-SNAPSHOT: Could not find artifact com.test.multiple:lib-project:jar:0.0.1-SNAPSHOT
My expectation stepwise on compilation of project-1
Check if there is a dependency for project-1
Go to ../lib-project
Compile and build it in target folder (or anywhere relative to our project)
Add this generated jar to "project-1" dependency
Compile and build the "project-1" jar file.
Parent Pom Configurations
<project ...>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.test.multiple</groupId>
<artifactId>parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>lib-project</module>
<module>project-1</module>
</modules>
</project>
** Lib project pom **
<project ...>
<parent>
<groupId>com.test.multiple</groupId>
<artifactId>parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>com.test.multiple</groupId>
<artifactId>lib-project</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>lib-project</name>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Project-1 pom
<project ...>
<parent>
<groupId>com.test.multiple</groupId>
<artifactId>parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>com.test.multiple</groupId>
<artifactId>project-1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>project-1</name>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.test.multiple</groupId>
<artifactId>lib-project</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
I have multiple spring boot projects, every project is independent and has its own CICD pipeline.
These projects need some common classes, I have created a separate project with common classes.
Congratulations, your projects are not independent any more!
Given the definitions above, here are the dependencies:
lib-project depends on parent;
project-1 depends on parent;
project-1 depends on lib-project.
Please check Introduction to the POM and Guide to Working with Multiple Modules for the discussion on the dependencies in Maven projects.
I cannot use any local or remote repository, to put the dependent jar in m2 using mvn clean install and then refer to it as dependency
Given this limitation, and dependencies listed above, the POMs and source files of all the projects have to be present on the disk for build purposes. The build process has to start from the parent folder. The build process has to build all modules at once.
Also, please consider using mvn clean verify instead of mvn clean install to avoid populating the local repository with the artifacts you are building.
A maven project isn't designed to build its dependencies on demand. However, jenkins can be configured to build downstream projects when changes are pushed to an upstream dependency.
I have also worked around this by using the -pl option on a parent pom in the relevant jenkinsfile to build a subset of the child projects
Jenkinsfile
clone parent project
mvn clean package -pl core,deployable

Maven child module in parent pom as dependency

I'm trying to create a maven spring-boot project with multiple modules. I have created a parent module with packaging type pom and many children submodules with packaging type jar.
So my parent's pom.xml looks like:
<groupId>Creator</groupId>
<artifactId>DPAI</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>starter</module>
<module>DatabaseApi</module>
...
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.4.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
One of submodules: starter contains only starting class annotated with #SpringBootApplicatoion and in its pom.xml there is a section with other child artifacts like:
<parent>
<artifactId>DPAI</artifactId>
<groupId>Creator</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>starter</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>Creator</groupId>
<artifactId>DatabaseApi</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
...
</dependencies>
So I'm trying to do some refactoring and move Main.class and all dependencies to my parent's pom, but it doesn't compile with error with message that my dependencies referencing itself.
In my opinion, the problem is that my parent pom contains section with it's own submodules. Parent of that submoduls is the same pom, where I try to add described dependencies
The parent.pom can't contain any java code, only Maven specifics e.g. See: https://howtodoinjava.com/maven/maven-parent-child-pom-example/#parent-content
Maybe tell us, what you want to achieve.
In a Maven multi module project you usually have a parent Pom (with packaging Pom) and several modules at the same level as you already set your project up.
Build the modules without dependecies on your code first, the the dependent modules: In your parent Pom change the order of the modules to
<modules>
<module>DatabaseApi</module>
<module>starter</module>
...
</modules>
So I'm trying to do some refactoring and move Main.class and all
dependencies to my parent's pom
I dont think this is possible. Your parent pom is actually of type pom, meaning you're not actually supposed to have any java code in it. Its meant to hold the versions of jars used in your child modules. You can relate this to the spring-boot-parent module. When we declare the spring-boot-parent module in a spring boot project, your adding your project as a child of the spring-boot-parent. And the parent will manage the versions of all of your dependencies.
I think the best way forward would be to maintain all your service related code in your spring-boot module. Filters, controllers,etc. The other stuff like your jdbc, integration layers can be maintained in other child modules and then referred to the spring module as jar references similar to your example.
So I'm trying to do some refactoring and move Main.class and all
dependencies to my parent's pom,
I'm not 100% sure if Maven would support something like the following in the parent POM itself:
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>DatabaseApi</artifactId>
<version>${project.version}</version>
</dependency>
...
</dependencies>
But for sure it won't support Java classes in a Module with pom-packaging (such as parent modules or multi-module modules). The compiler:compile goal etc. are not bound to any phase for pom-packaging by default. In other words: Maven does not compile Java classes for pom-modules by default.
My recommendation:
Keep the SpringBootApplication in a Java-based module. For Spring MVC/ WebFlux application I usually create a "-web" module with:
SpringBootApplication
web service controllers
http/ web filters
global configs such as: security, swagger, async
application.yml
...
It's also the module where I configure the Spring Boot Plugin to create an executable JAR.

best practice for making a maven parent project

I developped a multi-module project which is a kind of java web framework.
One of the submodules is a parent pom that I provide for the users of my framework. This parent configures plugins and dependencies for them.
My problem is that this parent pom must refers the sibling modules with their version, which is ${project.version}, and because of the maven project inheritance, the ${project.version} is not the one I want.
To illustrate, my framework projects structure looks like :
my-framework/
|_pom.xml
|_parent/
|_pom.xml
|_server/
|_pom.xml
|_ui/
|_pom.xml
and my parent pom looks like :
<project
....
<!-- General information -->
<modelVersion>4.0.0</modelVersion>
<artifactId>my-framework-parent</artifactId>
<packaging>pom</packaging>
<parent>
<groupId>my.framework</groupId>
<artifactId>my-framework</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<properties>
<my.framework.version>${project.version}</my.framework.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>my.framework</groupId>
<artifactId>my-framework-server</artifactId>
<version>${my.framework.version}</version>
</dependency>
<dependency>
<groupId>my.framework</groupId>
<artifactId>my-framework-ui</artifactId>
<version>${my.framework.version}</version>
</dependency>
</dependencyManagement>
...
</project>
Then, if a user uses this parent, as maven resolves ${project.version} in the context of the user's project, ${my.framework.version} will be the user's project version instead my framework's version.
To solve this I generated the parent pom I want thanks to the maven-resources-plugin and I overrided the maven-install-plugin behaviour to install the generated pom.
My solution looks tricky and I would like if someone who faced the same problem has a better solution?
I finally found a solution thanks to the flatten-maven-plugin.
But I had to post a pull request to support the pluginManagement section.
https://github.com/mojohaus/flatten-maven-plugin/pull/10
So the solution was to modify my parent pom thanks to this plugin before publishing it. As a result I can set the version I want instead of using ${project.version}.

How to use Maven Release Plugin with Multiple Maven Projects

I'm using Maven 3.
I have multiple maven projects, namely: the 'data model', the 'service', and the 'presentation', split into 3 different projects. They are configured separately (ie. not using maven parent pom).
I have maven release plugin setup on my project correctly, such that when I run mvn release:clean release:prepare release:perform on each individual project, it updates the project version (ie: from 3.4.5-SNAPSHOT to 3.4.5) as well as all the other things.
The problem here is, 'presentation' is dependent on 'service' is dependent on 'data model', and I refer to the projects in the pom files with the version number.
While I develop, say for example I would refer to 'service' in 'presentation' as 3.4.5-SNAPSHOT. But during deploy, I have to release 'service' to change the version to 3.4.5, then I have to update my version reference of 'service' in 'presentation', before I can run a release on 'presentation'.
Is there an automated way of doing this such that I don't need to update the reference of dependent projects during release?
What I have so from thanks to below comments: Updated: 25/03/2013
Run maven with:
versions:use-releases -Dmessage="update from snapshot to release" scm:checkin release:clean release:prepare release:perform
Outcome: version updated, but release build failed.
The Versions Maven Plugin may help you to achieve requirement, especially the goal versions:use-releases. You may be interested in the goal versions:use-next-releases and versions:use-latest-releases as well.
Side Note:
Normally, the good practice is define them as a Maven Multiple Module( here and here). This allow us to manage the version easier as the following example.
The parent
<groupId>my-group</groupId>
<artifactId>my-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
.....
<modules>
<module>my-model</module>
<module>my-service</module>
<module>my-ui</module>
</modules>
The my-model
<parent>
<groupId>my-group</groupId>
<artifactId>my-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>my-model</artifactId>
The my-service
<parent>
<groupId>my-group</groupId>
<artifactId>my-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>my-service</artifactId>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>my-model</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
The my-ui
<parent>
<groupId>my-group</groupId>
<artifactId>my-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>my-ui</artifactId>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>my-service</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
Regarding to the above example when we release, the related version will be updated based on the parent version automatically.

Clean up Maven dependency management

In a big Maven 2 project it is nice to have the dependency management to make sure that only one version of a dependency is used in the whole system. That makes the system consistent.
But when I generate effective POMs I have no chance to see where the dependency versions came from. Likewise in a POM at the top of the hierarchy I have no idea where in the child POMs the defined versions of the dependency management section are really used.
So how do I keep the dependency management cleaned up? When I remove a dependency in one project, I always check in all other projects if it is still needed at all, so that I can also remove in from the dependency management at the top?
Also, how do I build up the dependency management, making sure it is not duplicated somewhere in the child POMs? When I add dependencies I always check all other projects to see if it possibly could be aggregated on top in the dependency management? Or would you just always move all dependency versions to the top from the beginning so they are always in only one place?
Thanks for any thoughts.
You could create one or more boms (bill of materials) for your project. These pom.xmls will declare all the dependencies used in your project within dependencyManagement section.
In each child pom, you would import these boms and use those dependencies that are required for the project.
In this way, dependency versions are managed centrally, while at the same time, each child pom uses only those dependencies that it needs.
See Importing Managed Dependencies
BOM project
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>my.group</groupId>
<artifactId>My-Project-Bom</artifactId>
<version>1.0</version>
<packaging>pom</packaging>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.7.0</version>
</dependency>
...
</dependencies>
</dependencyManagement>
</project>
Child project
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>my.group</groupId>
<artifactId>child1</artifactId>
<packaging>jar</packaging>
<name>Child1</name>
<version>1.0</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>my.group</groupId>
<artifactId>My-Project-BOM</artifactId>
<version>1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
</dependency>
</dependencies>
...
</project>
maven dependency plugin has a few goals to help you get the dependency hierarchy.
mvn dependency:list
mvn dependency:tree
mvn dependency:analyze
If you are using eclipse, the m2eclipe plugin allows you to view the Dependency Hierarchy for you pom. This can be very useful when trying to determine where dependencies are brought into your project and where conflicts are occurring.
You should explicitly declare the dependencies in the projects in which they are used, unless it is being used in ALL of the projects. If, for example, Spring is used for all of your projects, then put that in the parent POM. If it is only used in some projects, declare it in each one and put a spring.version property in the parent which each child pom can use for its version.
Moving all dependencies to the parent removes the responsibility from each project to manage its own dependencies. I would consider this a misuse of maven as it makes things more difficult to maintain instead of easier. It now adds dependencies to projects that doesn't need them. Often the scope of a dependency is different for projects as well, and you cannot manage that unless you declare your dependencies locally.
You can get the POM to POM dependencies, and the code-references that cause them, using the Structure101 composition perspective. Create a new s101 project, type Maven, specify the root pom.xml file, finish (use defaults for the rest of the wizard), then select the composition perspective (2nd button down on the vertical toolbar top left of the UI) and you will see something like this:

Categories