Maven override parent dependency with specific dependency - spring-boot

I want to override parent spring-data-elasticsearch dependency with specific one.
pom.xml:
...
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.5</version>
<relativePath/>
</parent>
...
<dependencies>
...
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
<version>4.1.1</version>
</dependency>
</dependencies>
...
with this configuration i have 7.17.6 elasticsearch in libraries. i need 7.12.1 When i change the version to higher or lower version nothing changes, but when i change the paren version to 2.5.2 the elasticsearch version in libraries become 7.12.1 . My question is: How do i change the version of the dependecy without changing the parent version?
I have tried to exclude the dependency with tag but that didn't help me.

It seems that spring-data-elasticsearch/4.1.1 is dependent on elasticsearch up to v7.17.8 (not v7.12.1)
To override the dependency to elasticsearch in the parent you should use the dependencyManagement tag, as follows to use elasticsearch v7.12.1.
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>7.12.1</version>
</dependency>
</dependencies>
</dependencyManagement>
Putting the dependency outside the dependencyManagement tag will work but is incorrect.

Related

Flatten Plugin: Resolve dependencyManagement of bom without inherited

I created an example project for this problem: https://github.com/robeatoz/flatten-resolve-dependency-management-without-inherited
Following project structure is given:
foo-build as the parent for all modules
foo-module-a as child module
foo-module-b as child module
foo-module-c as child module
foo-dependencies as bom
I used the flatten-maven-plugin and the property revision for CI friendly builds in all modules:
<groupId>stack.overflow</groupId>
<artifactId>foo-build</artifactId>
<version>${revision}</version>
<packaging>pom</packaging>
<properties>
<revision>0.1-SNAPSHOT</revision>
</properties>
The parent (foo-build) manages one external dependency:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>external.artifact</groupId>
<artifactId>module-managed-in-parent</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>
</dependencyManagement>
The bom (foo-dependencies) manages the foo dependencies:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>stack.overflow</groupId>
<artifactId>foo-module-a</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>stack.overflow</groupId>
<artifactId>foo-module-b</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>stack.overflow</groupId>
<artifactId>foo-module-c</artifactId>
<version>${revision}</version>
</dependency>
</dependencies>
</dependencyManagement>
I want that the flattened pom of the bom contains only the resolved foo dependencies without the dependencies managed by the parent (foo-build) like this:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>stack.overflow</groupId>
<artifactId>foo-module-a</artifactId>
<version>0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>stack.overflow</groupId>
<artifactId>foo-module-b</artifactId>
<version>0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>stack.overflow</groupId>
<artifactId>foo-module-c</artifactId>
<version>0.1-SNAPSHOT</version>
</dependency>
</dependencies>
</dependencyManagement>
How do you have to configure the flatten-maven-plugin to achieve this?
I already tried <flattenMode>bom</flattenMode>, but then the flattened pom does not resolve the versions:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>stack.overflow</groupId>
<artifactId>foo-module-a</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>stack.overflow</groupId>
<artifactId>foo-module-b</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>stack.overflow</groupId>
<artifactId>foo-module-c</artifactId>
<version>${revision}</version>
</dependency>
</dependencies>
</dependencyManagement>
With the following configuration
<pomElements>
<properties>remove</properties>
<dependencyManagement>resolve</dependencyManagement>
</pomElements>
the flattened pom contains the managed dependency of the parent:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>stack.overflow</groupId>
<artifactId>foo-module-a</artifactId>
<version>0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>stack.overflow</groupId>
<artifactId>foo-module-b</artifactId>
<version>0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>stack.overflow</groupId>
<artifactId>foo-module-c</artifactId>
<version>0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>external.artifact</groupId>
<artifactId>module-managed-in-parent</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>
</dependencyManagement>
It would be simpler to change your approach to more client-centric:
Make foo-dependencies a root project (./pom.xml).
with only foo-* dependencies in dependency management section
modules list with a single foo-build module (would be truncated by flatten plugin)
generic project properties (would be truncated by flatten plugin)
Make foo-build an intermediate project (./foo-build/pom.xml).
with third-party dependencies in dependency management section
with build-specific properties or profiles, required by your project (if any)
Retain foo-module-* leaf modules with foo-build as a parent
If you insist on plain project structure (./foo-module-*/pom.xml), you can use relativePath to point parent module, e.g.:
<parent>
<groupId>stack.overflow</groupId>
<artifactId>foo-build</artifactId>
<version>${revision}</version>
<relativePath>../foo-build/pom.xml</relativePath>
</parent>
<artifactId>foo-module-a</artifactId>
This way you will receive:
clear foo-dependencies as you wish;
zero copy-paste for foo-* dependencies;
flexibility to build whatever and however you like in foo-build without side-effects on foo-dependencies (neither now nor in the future).
I have like the exact same usecase and I solved it with the following configuration.
You need to apply a very specific configuration to the flatten-plugin within the pom file of the BOM module:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>flatten-maven-plugin</artifactId>
<configuration>
<updatePomFile>true</updatePomFile>
<pomElements>
<dependencyManagement>expand</dependencyManagement>
</pomElements>
</configuration>
</plugin>
expand means that the dependencyManagement block will be replaced with the one from the effective pom where all references are properly resolved. updatePomFile is necessary because otherwise by default, the flattened pom would not be published for poms with <packaging>pom</packaging>
Here are the relevant parts from the flatten-plugin's documentation:
updatePomFile: https://www.mojohaus.org/flatten-maven-plugin/flatten-mojo.html#updatePomFile
Explanation for expand: https://www.mojohaus.org/flatten-maven-plugin/apidocs/org/codehaus/mojo/flatten/ElementHandling.html#expand
You don't need to change the version with ${revision}, use ${project.version}, take a try

Spring boot 2.1.7 having tomcat-embed-core conflit

I am migrating existing Spring project into Spring boot.unable to run spring boot application its showing following error.
The error log says there is a conflict on tomcat-embed-core.
In eclipse Dependency hierarchy of porm.xml is given below
i exclude the maven architect ,and try to run the application its showing following error
porm.xml
<modelVersion>4.0.0</modelVersion>
<artifactId>MyService</artifactId>
<packaging>jar</packaging>
<properties>
<java.version>1.8</java.version>
<!-- 2.1.3.RELEASE -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<springframework.boot.version>2.1.7.RELEASE</springframework.boot.version>
</properties>
<name>MyService</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.sybase.jdbc3.jdbc</groupId>
<artifactId>jconn3</artifactId>
<version>${jconn3.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-juli</artifactId>
<version>${tomcat.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
<version>${tomcat.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
what was wrong in this porm.xml
Where is
${tomcat.version}
defined?
That version probably does not match the tomcat version that auto magically is included with spring boot items.
And thus the conflict.
Go here:
https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web/2.1.7.RELEASE
And start following the COMPILE dependencies, and you'll find the versions that are auto included with 2.1.7.RELEASE. and you have to alter the other includes that are overwriting the springboot auto include tomcat versions.
Again, follow the COMPILED dependency trail.
So below is what you should find by crawling the COMPILED dependency trail (from immediately above in my answer)
https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-tomcat/2.1.7.RELEASE
And you'll find you need to set
tomcat.version to
9.0.22
By defining tomcat.version as 8.x, you are breaking it.
Another way to put it
You have to go ~way~ back to springboot 1.5.2.RELEASE or 1.5.3.RELEASE
https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-tomcat/1.5.2.RELEASE
https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-tomcat/1.5.3.RELEASE
(Again, in the two above links, looked at the COMPILE dependencies)
To find a version of tomcat (that is auto included with springboot) that gets close to tomcat 8.5.x (where 8.5.x is the one you are attempting to use)
That's pretty old.
The principal you are missing is that springboot auto includes dependencies. And anything else you import has to play nice with everything springboot auto includes.
And your current value for tomcat.version is NOT playing nice with everything springboot 2.1.7.RELEASE is auto including.
And now that you've been through all of that. You'll find you'll make your life easier if you engage the springboot world more completely.
Alot of times, springboot will have a (sub)package that will bring in the thing you really desire.
spring-boot-starter-jdbc
https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-jdbc/2.1.7.RELEASE
You would probably be better off bringing that package in, vs hand-picking ones. Aka, get rid of your "tomcat-jdbc" include and see if the spring-boot-starter-jdbc can give you what you want.
The curse/blessing of spring-boot is that it is its own universe. But if you engage, you probably want to play by its rules more often than not.
PS
It is pom.xml, not porm.xml
Try adding spring-boot-starter-tomcat as a dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
Remove tomcat-juli and tomcat-jdbc dependencies. If you need JDBC support, add the corresponding starter:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
If you use JSP views, you will probably need the following dependencies as well:
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
Also, pay attention to your dependencies versions. Spring Boot's parent POM defines version management for many common artifacts so you don't need to set the <version></version> for these libraries. See https://docs.spring.io/spring-boot/docs/2.1.7.RELEASE/reference/htmlsingle/#appendix-dependency-versions

Maven increase version for submodule only

The project structure is (all on same version 1.3.0, which is latest):
Parent
-childA
-childB
-childC
Parent's pom is:
<groupId>com.dev.bla</groupId>
<artifactId>Parent</artifactId>
<version>1.3.0</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.dev.bla</groupId>
<artifactId>childA</artifactId>
<version>${project.version}</version>
</dependency>
</...>
Now, I need to do some changes to childB only and not intending to increase Parent's version (No?).
So now my childB's POM looks like:
<parent>
<groupId>com.dev.bla</groupId>
<artifactId>Parent</artifactId>
<version>1.3.0</version>
</parent>
<groupId>com.dev.bla</groupId>
<artifactId>childB</artifactId>
<version>1.4.0</version>
<dependencies>
<dependency>
<groupId>com.dev.bla</groupId>
<artifactId>childA</artifactId>
</dependency>
</dependencies>
Now, when I'm trying to build Parent or childB, it fails because it figures (as I can see from effective POM) version of childA to 1.4.0 which does not exist as childA is at its latest 1.3.0. In short, {project.version} in Parent translates to 1.4.0 while according to my understanding it should've been translated to 1.3.0 only as childB has parent Parent with 1.3.0.
What am I missing?
I assume you got a Maven multi-module project. So, when you create the modules (childA & childB) it will automatically take the version from the parent POM.
So, remove the version tag (1.4.0) from the 'childB' POM declaration
<groupId>com.dev.bla</groupId>
<artifactId>childB</artifactId>
It's all about configuration inheritance. That means the following assumptions are not correct:
In short, {project.version} in Parent translates to 1.4.0
It's not in Parent, it's in childB since that is built and it inherits the {project.version} configuration from Parent and interpolates it to its own version.
according to my understanding it should've been translated to 1.3.0
No, see above.
If you prefer to keep different versions declare the following in Parent:
<properties>
<childA.version>1.3.0</childA.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.dev.bla</groupId>
<artifactId>childA</artifactId>
<version>${childA.version}</version>
</dependency>
</...>

Maven dependencyManagement: inherit dependency version from parent

I want my dependency in dependencyManagement block to inherit a version from spring-boot-parent's dependencyManagement block, but add exclusion to it, so that I don't need to specify that exclusion in each of child modules.
My parent pom inherits from spring-boot-parent:
<artifactId>my-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
<relativePath/>
</parent>
<dependencyManagement>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>???</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencyManagement>
child pom inherits my-parent:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
</dependencies>
I tried several approaches:
When I replace ??? with ${parent.version}, in child module this version is resolved to be my-parent's version: 1.0.0-SNAPSHOT, which is incorrect.
When I replace ??? with ${parent.parent.version}, maven breaks, as it doesn't support such properties
I can fix ??? to be 2.0.1.RELEASE and this will work fine, but if I update the version of spring boot, I have to remember to update the version of this dependency also, which is non-intuitive
I cannot extract 2.0.1.RELEASE as a property in my-parent and use that property as parent version, as maven does not support that.
I could've used property with value 2.0.1.RELEASE inherited from spring-boot-parent pom, but there is none such property, as far as I can see.
Is there a nice way to achieve what I want?
See Possible to have the parent version as Property to give to the children? - the version used to declare your parent can't be repurposed in a way that says "make this reference fixed to mean its interpretation at this point in the graph". Strings are strings and placeholders are placeholders; there's no built-in facility to have some kind of in-between thing. If the parent uses a property to define a dependency version you can reference that property; if it uses a fixed string (as in your case) then you'll need to repeat something in order to define an exclusion. As referenced in the linked question, a common way is something like this:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
</parent>
<properties>
<spring.boot.version>2.0.1.RELEASE</spring.boot.version>
</properties>
<dependencyManagement>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>${spring.boot.version}</version>
<exclusions>
...
You still have to repeat the value in two fields -- so you have to make very sure that you always keep those in sync (parent version and property).
However, the increasingly-popular way to manage this is to declare those versions in a BOM (a "bill-of-materials" pom with the specific purpose of keeping a set of components aligned). Then the dependencyManagement stuff can be imported instead of inherited. Spring Boot has been doing this for a while now; in fact the parent in your example doesn't actually declare the dependencies itself, they come from a different artifact. So instead of inheriting from the parent, you could do something like this (I might have the sequence of these backwards -- I can't remember whether first or last wins):
<properties>
<spring.boot.version>2.0.1.RELEASE</spring.boot.version>
</properties>
<dependencyManagement>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>${spring.boot.version}</version>
<exclusions>
...
... now, if there are other reasons (beyond just dep mgmt) you wanted to inherit from spring-boot-starter-parent then this won't really help your problem; you'll still need to duplicate. But I suspect that as your project matures you'll want to have a parent of your own devising anyway.

Dependeny Management using POM import

I am creating a project 'test-jar' in my local and i am using pom file which I don't have write access as Parent of 'test-jar' project. The parent project has already defined depedencyManagement with old versions.
As I have to update dependency versions in my project and planning to override parent's dependency Management. So, I have created another POM file with my own dependency Management and imported into 'test-jar' project.
My Project :
<project>
<artifactid>test-jar</artifactid>
<parent>
<artifactId> test-parent </artifactId>
</parent>
<dependencies>
<dependency>
<artifactId>jar/artifactId>
</dependency>
<dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<artifactId>custom-pom</artifactId>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencyManagement>
</project>
My Parent Project:
<project>
<artifactid>test-parent</artifactid>
<dependencyManagement>
<dependencies>
<dependency>
<artifactId>jar/artifactId>
<version>1.0</version>
</dependency>
</dependencyManagement>
</project>
My Custom POM for updated dependencyManagement:
<project>
<artifactid>custom-pom</artifactid>
<dependencyManagement>
<dependencies>
<dependency>
<artifactId>jar</artifactId>
<version>3.0</version>
</dependency>
</dependencyManagement>
</project>
The problem is, I am always getting dependency version from parent pom, though i have imported new dependency management in project.
I am using Maven 2.2.1 version here.
Is there any solution how to overwrite Dependency Management from Parent POM ?
Based on the documentation:
This scope is only used on a dependency of type pom in the
section. It indicates that the specified POM
should be replaced with the dependencies in that POM's
section. Since they are replaced, dependencies
with a scope of import do not actually participate in limiting the
transitivity of a dependency.
Apart from your problem you can simply use differerent version which are different of the onses defined in the parent pom's dependencyManagement. Furthermore you could create a separate pom wich defines the dependencies with new version (dependencyManagement) and inherits from the given parent.

Resources