maven parent pom dependency-management in gradle - maven

In maven, you can declare depenencies versions in dependency management section.
Say I have such pom for managing default versions of some libraries for all of my projects (so I don't have to repeat them all over again and so I can ensure some consistency across all of my projects).
Then I have multiple projects(project A and project B) which have this pom set as parent pom. If in project A I want to use spring.jar, and I have spring.jar defined in dependency-management of A's parent pom, I don't have to define spring version in A's pom again, I just define that it depends on spring. So far it's ok, is pretty simple how to do it in gradle too (http://stackoverflow.com/questions/9547170)
What I'm wondering about is this situation:
Imagine that spring 3.0 depends on hibernate 3.0. In A's parent pom I have defined hibernate dependency in dependency-management section with version 3.1, but spring is not defined there. Spring is defined in A's pom (with version 3.0). Dependency resolution in maven for project A would result in fetching spring 3.0 and hibernate 3.1 - because despite fact that spring 3.0 depends on hibernate 3.0, dependency-management of A's parent pom overrides hibernate version, so 3.1 would be used instead.
Is there way of defining something similar in gradle? Note that I didn't have to specify hibernate in A's pom specificly and also it is not specified as dependency in A's parent pom - it is only in dependency-management section of A's parent pom.

The io.spring.dependency-management plugin allows you to use a Maven bom to control your build's dependencies:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath "io.spring.gradle:dependency-management-plugin:0.5.3.RELEASE"
}
}
apply plugin: "io.spring.dependency-management"
Next, you can use it to import a Maven bom:
dependencyManagement {
imports {
mavenBom 'io.spring.platform:platform-bom:1.1.4.RELEASE'
}
}
Now, you can import dependencies without specifying a version number:
dependencies {
compile 'org.springframework:spring-orm'
compile 'org.hibernate:hibernate-core'
}

Related

Maven dependency BOM camel-spring-boot-bom not working with Gradle

I'm trying to get the Apache Camel Spring Boot BOM working. However, it does neither work by
specifying it as a dependency with
dependencies {
implementation platform("org.apache.camel.springboot:camel-spring-boot-bom:${camelVersion}")
.
.
.
}
or
dependencies {
implementation "org.apache.camel.springboot:camel-spring-boot-bom:${camelVersion}"
.
.
.
}
Nor by using the dependencyManagement imports alongside other that are working
dependencyManagement {
imports {
mavenBom SpringBootPlugin.BOM_COORDINATES
mavenBom "org.junit:junit-bom:${junitVersion}"
mavenBom "org.apache.camel:camel-bom:${camelVersion}"
mavenBom "io.github.openfeign:feign-bom:${feignVersion}"
mavenBom "org.apache.camel.springboot:camel-spring-boot-bom:${camelVersion}"
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
together with the actual dependencies (without versions specified explicitly)
implementation "org.apache.camel.springboot:camel-csv-starter"
implementation "org.apache.camel.springboot:camel-rest-starter"
implementation "org.apache.camel.springboot:camel-seda-starter"
implementation "org.apache.camel.springboot:camel-direct-starter"
implementation "org.apache.camel.springboot:camel-jackson-starter"
implementation "org.apache.camel.springboot:camel-servlet-starter"
implementation "org.apache.camel.springboot:camel-zipfile-starter"
implementation "org.apache.camel.springboot:camel-resilience4j-starter"
implementation "org.apache.camel.springboot:camel-rest-openapi-starter"
implementation "org.apache.camel.springboot:camel-platform-http-starter"
implementation "org.apache.camel.springboot:camel-spring-boot-starter"
implementation "org.apache.camel.springboot:camel-platform-http-starter"
implementation "org.apache.camel.springboot:camel-spring-boot-dependencies"
and in both ways I'm getting
> Could not resolve all dependencies for configuration ':my-project:compileClasspath'.
The project declares repositories, effectively ignoring the repositories you have declared in the settings.
You can figure out how project repositories are declared by configuring your build to fail on project repositories.
See https://docs.gradle.org/7.5.1/userguide/declaring_repositories.html#sub:fail_build_on_project_repositories for details.
> Could not find org.apache.camel.springboot:camel-spring-boot-dependencies:.
Required by:
project :my-project
while directly using version numbers in individual dependencies like
dependencies {
implementation "org.apache.camel.springboot:camel-spring-boot-starter:${camelVersion}"
}
is perfectly working.
Why does it seem the Spring Boot Camel BOM is working "differently" than the other dependencies and how do I get it working?
The bom 'dependency' is actually just a reference for which version to use for any dependency you bring in within dependencies{ } specified in the bom (including transitive).
So for example:
dependencies {
implementation "org.apache.camel.springboot:camel-spring-boot-starter"
}
dependencyManagement {
imports {
mavenBom "org.apache.camel.springboot:camel-spring-boot-bom:${camelVersion}"
}
This code above if you see, camel-spring-boot-starter does not have a version specified to it, but it is still able to resolve because the version is specified within the bom file of camel-spring-boot-bom:${camelVersion}.
And just in case for reference here you can find the dependencies and the version your dependencies will resolve with, for example version 3.20.0 of bom: https://mvnrepository.com/artifact/org.apache.camel.springboot/camel-spring-boot-bom/3.20.0
I mistakenly had a second BOM org.apache.camel.springboot:camel-spring-boot-dependencies listed as a dependency, which caused the problem when I was removing the version number.
I've removed that from the dependencies now and used it as the BOM, as it fits my needs better.
According to the docs:
There is a curated camel-spring-boot-dependencies which is a generated
BOM that has adjusted the JARs that both Spring Boot and Apache Camel
may use to use single shared version that will not conflict. This BOM
is what is used to test camel-spring-boot itself. However Spring Boot
users may want to use pure Camel dependencies and hence why you can
use camel-spring-boot-bom that only has the Camel starter JARs as
managed dependencies. This may lead to a classpath conflict if a 3rd
party JAR from Spring Boot is not compatible with a Camel component.
https://camel.apache.org/camel-spring-boot/3.19.x/index.html#_camel_spring_boot_bom_vs_camel_spring_boot_dependencies_bom

Gradle BOM project

I am working on a task where parent project with all the required dependencies are mentioned in gradle and this project to be used as parent, basically a BOM which has all the components mentioned and can be usedrefered as dependency in other project
Say for example, Spring boot parent and other dependencies are mentioned in gradle file, which I can refer this project in other projects.
The projects are not in multi module structure.
Maven equivalent:
<dependencyManagement>
<dependencies>
<dependency>
</dependency>
</dependencies>
</dependencyManagement>
similar tags - pluginManagement, build, profiles etc
If you can refer me to the resources or some head start would be helpful.
Thanks.
Sharing common dependency version across projects can be accomplished using a platform:
A platform is a special software component which can be used to control transitive dependency versions. In most cases it’s exclusively composed of dependency constraints which will either suggest dependency versions or enforce some versions. As such, this is a perfect tool whenever you need to share dependency versions between projects.
With the Java Platform plugin, you can create a project to accomplish this (Gradle does not have a 1:1 equivalent of parent):
// build.gradle
// Let's call this project com.example:my-parent-bom
plugins {
id 'java-platform'
}
javaPlatform {
allowDependencies()
}
dependencies {
// Import other BOMs
api platform('org.springframework.boot:spring-boot-dependencies:2.4.4')
api platform('org.springframework.cloud:spring-cloud-dependencies:2020.0.2')
// Define version for dependencies not managed by the above BOMs
constraints {
api 'commons-httpclient:commons-httpclient:3.1'
runtime 'org.postgresql:postgresql:42.2.5'
}
}
Then you can publish this platform like any other Gradle project and consume it:
// some other build.gradle
plugins {
id 'java'
}
dependencies {
implementation platform('com.example:my-parent-bom')
}

how to declare dependency version in one place for many gradle projects

I work on a project with multiple grails services, plugins and libraries, all built with gradle with their dependencies declared in build.gradle files, one per project, this makes sense, I hope.
In maven I used to be able to declare versions of all dependencies in one parent project pom, or a pom template, and only include the dependencies in the projects that required them without the versions. This made upgrading dependencies easy in one place. Is there a simple way to do this in gradle?
Pseudocode example:
master_template/build.gradle
dependencies {
joda-time:joda-time:2.9.1
cglib:cglib:3.2.9
javax.servlet:javax.servlet-api:3.1.0
}
service_a/build.gradle
parent: master_template
dependencies {
joda-time:joda-time
javax.servlet:javax.servlet-api
}
service_b/build.gradle
parent: master_template
dependencies {
cglib:cglib
javax.servlet:javax.servlet-api
}
You can create a multi module project like you would do in maven with a parent pom.
In order to manage the dependency in the parent, I use the spring dependency management plugin.
You parent build.gradle would look like:
subprojects {
apply plugin: "io.spring.dependency-management"
sourceCompatibility = 1.8
targetCompatibility = 1.8
check.dependsOn dependencyCheckAggregate
repositories {
mavenLocal()
jcenter()
// other repos
}
dependencyManagement {
def jacksonVersion = "2.+"
dependencies {
dependency "com.fasterxml.jackson.core:jackson-annotations:$jacksonVersion"
dependency "com.fasterxml.jackson.core:jackson-core:$jacksonVersion"
dependency "com.fasterxml.jackson.core:jackson-databind:$jacksonVersion"
dependency "com.fasterxml.jackson.datatype:jackson-datatype-jdk8:$jacksonVersion"
dependency "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:$jacksonVersion"
}
}
}
Now, you can add dependencies to your submodules without specifying version.
You can easily achieve what you want by using Gradle's default apply from: 'other.gradle', so no additional plugins are needed.
In my micro-service project I'm using something like that:
common-gradle/env.gradle
apply plugin:'groovy'
ext.compile = [ 'joda-time:joda-time:2.9.1', 'cglib:cglib:3.2.9` ]
ext.testCompile = [ 'org.spockframework:spock-core:1.3-groovy-2.5' ]
common-gradle/dependencies.gradle
dependencies {
compile ext.compile
testCompile ext.testCompile
}
And the usage
service_a/build.gradle
apply from:'../common-gradle/env.gradle'
ext.compile << 'ch.qos.logback:logback-classic:1.2.3'
apply from:'../common-gradle/dependencies.gradle'
Thus each of my build.gradle files contain only 3-5 lines of critical information like project name and version.
You don't need to import the common-gradle as a project in your IDE, you can simply use symlinks to avoid using external references. Also during build on a Jenkins-like pipeline, the only thing you have to do is to check out the common-gradle repo into your working dir.

Replicating Maven "dependencyManagement" tag from inside Gradle build

I am trying to follow this Spring Boot/Vaadin guide however I'm using Gradle, not Maven.
At the very top of that guide they say to use the following Maven XML:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-bom</artifactId>
<version>10.0.11</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
However I don't see a dependencyManagement task available via Gradle. So I ask: how do I replicate the same behavior as the <dependencyManagement/> XML element above over in "Gradle land"?
Update: current attempt
dependencyManagement {
imports {
mavenBom 'com.vaadin:vaadin-bom:10.0.11'
}
}
Only problem with this is that when I add it to my build.gradle and then run ./gradlew clean I get the following Gradle error:
"Could not find method dependencyManagement() for arguments..."
This should give you a working build:
plugins {
// the Gradle plugin which provides the “dependencyManagement” block
id 'io.spring.dependency-management' version '1.0.6.RELEASE'
// add Java build functionality to be able to follow the Vaadin guide
id 'java'
}
dependencyManagement {
imports {
// the Maven BOM which contains a coherent set of module versions
// for Vaadin dependencies
mavenBom 'com.vaadin:vaadin-bom:10.0.11'
}
}
repositories {
// find dependency modules on Maven Central
mavenCentral()
}
dependencies {
// the dependency module you need according to the Vaadin with
// Spring Boot guide; the version of the module is taken from the
// imported BOM; transitive dependencies are automatically taken
// care of by Gradle (just as with Maven)
compile 'com.vaadin:vaadin-spring-boot-starter'
}
Run ./gradlew dependencies --configuration compileClasspath to see that all dependencies are available on your Java compile classpath now.
Edited to reply to the question in the comments: indeed, the import of the BOM leads to a slightly different set of dependencies than would be used without it. You can see the dependencies difference like so:
./gradlew dependencies --configuration compileClasspath > with-BOM.txt
Remove the dependencyManagement block and add a version to the single dependency: compile 'com.vaadin:vaadin-spring-boot-starter:10.0.11'
./gradlew dependencies --configuration compileClasspath > without-BOM.txt
diff -u with-BOM.txt without-BOM.txt
You can see slight differences like org.webjars.bowergithub.webcomponents:webcomponentsjs:1.2.6 being used with the BOM and version 1.2.2 without it. The reason for that can be found in the BOM where version 1.2.6 is defined and where the authors also mention the reason for that: “Transitive webjar dependencies, defined here for repeatable builds”
Generally maven dependencyManagement tag is used to import bom or control transitive versions.
Gradle does that with platform component, like below example.
dependencies {
implementation platform('com.vaadin:vaadin-bom:10.0.11')
implementation ('com.vaadin:vaadin-core')
}
This does not force you to depend on spring plugin for importing bom.

Gradle: Compile Dependencies

I'm using mongodb with Spring Boot. Recently, my mongodb was upgraded to version 3.0.
I'm using the following Gradle dependencies for Spring:
buildscript {
ext {
springBootVersion = '1.2.6.RELEASE'
}
dependencies {
compile 'org.springframework.boot:spring-boot-starter-data-mongodb'
}
If I look on maven repositories for Gradle: 'org.springframework.boot:spring-boot-starter-data-mongodb:1.2.6.RELEASE', I see the following (http://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-mongodb/1.2.6.RELEASE):
The dependencies for the mongo-java-drivers are 2.12.5 under the "Version" column. I was wondering what the "Update" column is there for and how can I use the version of the mongo-java-drivers listed there instead (3.0.4)?
Since I'm using mongo 3.0, I would like to use the 3.0.4 java-drivers instead of 2.12.5 as I need to update my java-drivers to be at least 2.13 before they will work with my mongodb 3.0: http://docs.mongodb.org/manual/release-notes/3.0-scram/#upgrade-drivers
Just add the following dependency to your project dependencies:
compile 'org.mongodb:mongo-java-driver:3.0.4'
This will explicitly set there mongodb Java driver to the newest version and will overrun the transitive dependency version of spring-boot-starter-data-mongodb.
BTW, the "Updates" column means the newest version for a specific Artifact.
You can force the usage of a newer version of a dependency by just explicitly adding the dependency version that you want to use in the pom.xml.
Then Maven will use the explicitly specified version to compile.
FYI, you can exclude a dependency triggered by a direct dependency by using the exclude element.
See this doc to know how maven manages dependencies.
If you are using Gradle, see this page. In fact, you exclude the MongoDB transitive dependency triggered by spring boot and you explicitly add the latest version as a direct dependency.

Resources