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.
Related
I have created 5 or 6 Java projects in Eclipse by now and will be creating some 20 more projects. I have to add the TestNG library and another library (including some specific jar files) in the project.
Is there any way such that the Eclipse will automatically include both of these libraries at the time of creating every new project?
I don't want to add these libraries on my own by navigating to ADD BUILD PATH -> ADD LIBRARIES.
First, you shouldn't use Eclipse dependency management (add libraries manually to build path using Eclipse) if you're already using Maven.
IMO, you should only rely on Maven dependency mangement.
I suggest you to create a Maven parent project that will handle your dependecies used across multiple projects as follow.
Project structure
- maven-parent-project
|-- project-a
|-- project-b
|-- ...
Define Maven parent project
I suggest you used <dependencyManagement> (documentation) to manage the versions of your dependencies.
pom.xml
<project>
<artifactId>maven-parent-project</artifactId>
<modules>
<module>project-a</module>
<module>project-b</module>
</modules>
<dependencyManagement>
<dependencies>
<!-- Here you can define the versions of your dependencies used accross multiple project -->
</dependencies>
</dependencyManagement>
<dependencies>
<!-- Here you can define the dependencies used accross multiple project -->
</dependencies>
</project>
Define Maven sub projects
Then, you can define in all your project the maven-parent-project
pom.xml
<project>
<parent>
<artifactId>maven-parent-project</artifactId>
<version>0-SNAPSHOT</version>
<groupId>group</groupId>
</parent>
<artifactId>project-a</artifactId>
<dependencies>
<!-- Here you can define the dependencies specific to the project a -->
</dependencies>
</project>
I hope this will help you.
Study about dependency management in Maven. That will solve your requirements. Read this thread to get the jist.
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}.
I'm working with Maven to management the dependencies of my projects. I have my parent POM and I'm using Dependency Management to avoid write the common dependencies in each project.
Now, I need change the version of one dependency in my child POM.
I have this of my parent POM
<dependencyManagement>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.1</version>
</dependency>
</dependencyManagement>
My child POM has a reference to the parent POM
<parent>
<groupId>com.myproject</groupId>
<artifactId>root-parent-pom</artifactId>
<version>1.1.0.22</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>
And in this child POM I want to override the version of the same dependency that I wrote in the parent POM, something like this.
<dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
</dependency>
I did that, but when I generate my project, in this case is a WAR, the final version of the dependency that is included in my project is the version that is described on the parent POM.
Is possible override the version in child POM?
Maybe. If you specify a distinct version, then this version will override the one in the dependencyManagement element.
But only for this single POM. It doesn't magically distribute to the next POM in the reactor build unless the next POM has this POM as parent. So if you have this setup:
parent
- mod1
- mod2
- war
and you put this into mod1, then the war won't notice since war uses parent as parent POM. The dependency mod1 says "please use 2.6" but that's the same as any other pom which uses 2.1 - there is no reason to prefer that over the other. That's the power of dependencyManagement: You get a single place where you can control the versions of all transitive dependencies.
Try mvn help:effective-pom to see what Maven will use in each part of your build.
To make the WAR pick up the overwritten version, you need to specify it in the parent POM of the WAR or in the WAR's POM itself.
The usual solution is to have a parent POM for all projects which sets the default versions (2.1). Then you have a parent POM per project which inherits from the global parent POM. Here you can set the version to 2.6. Since all modules of the project inherit from it, the per-project parent POM takes precedence.
You need to define that dependency in a war project.
Is it possible to use an aggregating module (pom that aggregates modules for building purposes) as a dependency that transitively includes its modules as dependencies? Considering it must declare those dependencies that correspond to its submodules, otherwise if you declare it as a dependency, it hasn't own dependencies, so that no transitive deps are included.
I already tried it but I got a cyclic dependency error.
Otherwise I would have to create an extra module (say my_module_deps) that just declares all those dependencies, so I could use it as a dependency that transitively includes its dependencies. I don't like having maven modules that do not have any specific purpose except for being a dependency bulk.
This is the desired state, so I can use it for both module aggregation and a dependency to be used for getting its transitive dependencies :
<project>
<artifactId>aggregationModule</artifactId>
<modules>
<module>a</module>
<module>b</module>
<module>c</module>
</modules>
<dependencies>
<dependency>
<artifactId>a</artifactId>
</dependency>
<dependency>
<artifactId>b</artifactId>
</dependency>
<dependency>
<artifactId>c</artifactId>
</dependency>
</dependencies>
</project>
Do any of the sub-modules have that aggregating project defined as its parent?
If so, this cannot work, since for being parent the project must be build first.
But if the parent itself defines the modules as dependencies at the same time, the modules must be build first, so you created your cyclic dependency error.
You cannot declare a dependency to a project with packaging type "pom". If you do so maven will show the same error as when you declare a dependency to a jar module which does not exists in your local repository and could not be downloaded from your repository list.
Maybe some of the alternatives proposed to this question could help you.
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: