Is there any replacement of dependencyManagement.importedProperties in Gradle 5? - java

I need to get a property like "jackson.version" from a BOM similar to org.springframework.boot.spring-boot-dependencies. I know I can do this with io.spring.dependency-management plugin by using dependencyManagement.importedProperties. But what is a way to this with Gradle's 5 Maven BOM support?
This is an example with io.spring.dependency-management(Kotlin DSL):
dependencyManagement {
imports {
mavenBom("org.springframework.cloud:spring-cloud-dependencies:Greenwich.RELEASE")
}
}
dependencies {
implementation("org.group:artifact:${dependencyManagement.importedProperties["spring-cloud-aws.version"]}")
}
I'd like to do the same with Gradle 5:
dependencies {
implementation(platform("org.springframework.cloud:spring-cloud-dependencies:Greenwich.RELEASE}"))
implementation("org.group:artifact:${?["spring-cloud-aws.version"]}")
}
How to get "spring-cloud-aws.version"(any property from the BOM)?

Currently no. There are many features that are not yet available. You can plan to see it implemented in later versions of Gradle or more likely an equivalent functionality.
See this detailed video below on the comparison of Spring Dependency management and Gradle 5's support for importing BOMs:
Managing Dependencies for Spring Projects with Gradle by Jenn Strater and Andy Wilkinson

Related

how to choose between versions in build.gradle

if you have a build.gradle file with the line implementation 'org.springframework.boot:spring-boot-starter-web', how do you choose the version of the jar it downloads so that you get the latest one? I've seen a project where it is a 2.2.4 release, but in another project I've seen the same line with a 2.2.5 release.
Since you dropped the name Spring Boot, I assume the project has been generated Spring Initializr. A project generated with the Initializr has two plugins applied:
org.springframework.boot (Reference Documentation)
io.spring.dependency-management (Reference Documentation)
io.spring.dependency-management is Spring's opinionated way to provide Maven-like dependency management to Gradle builds. It allows to declare dependency versions once and then omit the version when declaring the actual dependency.
The org.springframework.boot plugin does the following:
When you apply the io.spring.dependency-management plugin, Spring Boot’s plugin will automatically import the spring-boot-dependencies bom from the version of Spring Boot that you are using. This provides a similar dependency management experience to the one that’s enjoyed by Maven users. For example, it allows you to omit version numbers when declaring dependencies that are managed in the bom. To make use of this functionality, simply declare dependencies in the usual way but omit the version number.
(From: Managing Dependencies)
What does that mean in practice?
When you generate a project for Spring Boot 2.1.14, your build.gradle will look similar to this:
plugins {
id 'org.springframework.boot' version '2.1.14.RELEASE'
id 'io.spring.dependency-management' version '1.0.9.RELEASE'
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
}
The org.springframework.boot plugin instructs the io.spring.dependency-management to apply the bill of materials (BOM) of Spring Boot 2.1.14. The BOM declares the following version for spring-boot-starter-web:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.14.RELEASE</version>
</dependency>
(From: Maven Central)
And this combination allows to declare the dependency to spring-boot-starter-web in the build.gradle without providing an actual version:
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
}
If you would change the version of the org.springframework.boot Gradle plugin, then a different version that matches the Spring Boot versions would be applied.
You may ask, why this tremendous effort?
We take an opinionated view of the Spring platform and third-party libraries so you can get started with minimum fuss.
That's why.
One possible solution is to use lockfiles and a version of +, or a combination of major.minor.+ or major.+
implementation 'org.springframework.boot:spring-boot-starter-web:+'
For more information on dependency locking: https://docs.gradle.org/current/userguide/dependency_locking.html
Another approach, and one I'm quite pleased with where available, is using a bill of materials, which specifies versions for a lot of dependencies, by introducing constraints. So where a dependency is used, with no version specified, as in your example, it will get the version the BOM brings in. So for the dependency below, if it is present in the BOM, it will match
implementation 'org.springframework.boot:spring-boot-starter-web
You're also free to override versions manually, by still specifying the version, should you choose to. And a BOM is like any other dependency, so you can use a mixture of lockfiles and BOMs.
Here's gradle documentation on bill of materials: https://docs.gradle.org/current/userguide/platforms.html

Build JAR with a dependency from the custom repository

I'm trying to build a JAR artifact which requires a custom dependency from the bintray repository, like:
https://dl.bintray.com/foo/bar
Is it possible to instruct the project that consumes such a library that it should resolve dependencies in the extra repository?
Or should I take another approach to provide it?
TL;DR
Build a fat jar including your dependencies.
Long Version
Yes, it is potentially possible to instruct a project that consumes your Gradle plugin to download plugin dependencies from a non-default repository. But it requires the user intervention which is probably not what you want to hear.
The following settings.gradle should retrieve your plugin from the Gradle Plugin Portal and resolve the dependencies from your Bintray repository:
pluginManagement {
repositories {
maven {
url 'https://dl.bintray.com/foo/bar'
}
gradlePluginPortal()
}
}
This is documented under Plugin Management.
Please note that I'm a bit vague in my answer since I never did something similar. What I can tell is that the spring-cloud-contract plugin does exactly this for snapshot versions.
IMHO, in your specific case, you get the best user experience by building a fat jar that includes your dependencies. A remarkable companion being the Gradle Shadow Plugin. It also features additional functionality for Gradle plugins, should you ever need them.

JUnit5 (aggregator) provides old dependencies [duplicate]

I am using Gradle 5's BOM (Bill of Materials) feature. This is how I describe it for my JUnit 5 dependencies:
testImplementation(enforcedPlatform("org.junit:junit-bom:5.4.0")) // JUnit 5 BOM
testImplementation("org.junit.jupiter:junit-jupiter-api")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
testImplementation("org.junit.jupiter:junit-jupiter-params")
My assumption is that providing the BOM will resolve the versions of the dependencies to 5.4.0. However, they get resolved to 5.1.1. I am not sure why. (I also request enforcedPlatform() to lock the specified version)
Inspecting JUnit 5's BOM we see that all org.junit.jupiter dependencies are listed with version 5.4.0 (resolving to 5.1.1 in the project) and all org.junit.platform dependencies are listed with version 1.4.0 which resolve correctly in the project.
I am not sure what I am missing and was hoping to get some help here. Thanks!
EDIT:
I used Sormuras response and moved all BOMs at the top of the dependencies {} block but was still not getting version 5.4.0. Then I suspected it might be coming from the Gradle Spring Dependency Management plugin that I use, so when I commented it out, I got version JUnit 5.4.0. How do I disable JUnit coming from the Gradle Spring Dependency Management plugin?
FINALLY:
I decided to use the Spring Boot Dependencies BOM directly and remove the Gradle plugin:
implementation(platform("org.springframework.boot:spring-boot-dependencies:2.0.5.RELEASE"))
I imagine the plugin was created for those version of Gradle before Gradle 5 where you couldn't use a BOM file. Now with the BOM support I can directly include it. This way my version of JUnit is as I have specified it in the enforcedPlatform() block.
I accepted Sam Brannen's answer below because he explains well how the issue occurs and what solves it and I think it's relevant for those who use older versions of Gradle.
How do I disable JUnit coming from the Gradle Spring Dependency Management plugin?
For starters, if you are using the dependency management plugin from Spring, you should not be importing the junit-bom since that results in duplicate (and potentially conflicting) management of those dependencies.
Aside from that, whenever you use the dependency management plugin from Spring and want to override a managed version, you have to do it by overriding the exact name of the version defined in the BOM used by the plugin.
This is documented in Spring Boot for Gradle and for Maven.
For Spring Boot the name of the JUnit Jupiter version is "junit-jupiter.version". You can find the names of all managed versions for Spring Boot 2.1.2 here.
So, in Gradle you would override it as follows.
ext['junit-jupiter.version'] = '5.4.0'.
You can see that I have done exactly that here.
With Maven you would override it as follows.
<properties>
<junit-jupiter.version>5.4.0</junit-jupiter.version>
</properties>
Further background information here: https://docs.spring.io/platform/docs/current/reference/html/getting-started-overriding-versions.html
JUnit 5.4.0 simplified its artifacts, and now delivered a single artifact for Jupiter - org.junit:junit-jupiter. I.e., you should simplify your Gradle file too:
testImplementation(enforcedPlatform("org.junit:junit-bom:5.4.0")) // JUnit 5 BOM
testImplementation("org.junit.jupiter:junit-jupiter")
Ensure to include JUnit's BOM before other BOMs that also refer to JUnit. First BOM wins and locks version of all later artifacts.
See this issue for a similar setup using Maven and Spring Boot: https://github.com/sormuras/junit-platform-maven-plugin/issues/29#issuecomment-456958188

How to use a parent in Gradle across different projects? [duplicate]

At my work we use Maven. I am going to try gradle for the first time. We use a common parent pom for all project which has setting for commonly used maven plugins and few comon dependencies. Is there a similar option available in gradle?
My second question is regarding release management. We use maven release plugin, which works pretty good for us. Is there something similar available in Gradle?
To share stuff within multiple projects of the same build, use allprojects { ... }, subprojects { ... }, etc. Also, extra properties (ext.foo = ...) declared in a parent project are visible in subprojects. A common idiom is to have something like ext.libs = [junit: "junit:junit:4.11", spring: "org.springframework:spring-core:3.1.0.RELEASE", ...] in the top-level build script. Subprojects can then selectively include dependencies by their short name. You should be able to find more information on this in the Gradle Forums.
To share logic across builds, you can either write a script plugin (foo.gradle), put it up on a web server, and include it in builds with apply from: "http://...", or write a binary plugin (a class implementing org.gradle.api.Plugin), publish it as a Jar to a repository, and include it in builds with apply plugin: ... and a buildscript {} section. For details, see the Gradle User Guide and the many samples in the full Gradle distribution.
A current limitation of script (but not binary) plugins is that they aren't cached. Therefore, a build will only succeed if it can connect to the web server that's serving the plugin.
As to your second question (which should have been a separate question), there are a couple of third-party release plugins available, for example https://github.com/townsfolk/gradle-release.
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.1.RELEASE'
}
}
Now, you can import dependencies without specifying a version number:
dependencies {
compile 'org.springframework:spring-core'
}
I think the best way to do things like maven parent pom is to to use gradle "apply from".
Something like this:
allprojects { // or: subprojects { ... }
apply from: "gradle/script/common.gradle"
}
The link and be a related path or an URL. Hope it helps.
Reference:
Import a Gradle script from the root into subprojects
Super POM, Parent POM type of hierarchy management in Gradle
I too wanted this type of feature, I have created a plugin to provide this here: https://github.com/boxheed/gradle-pater-build-plugin
You can convert the Parent pom content in to Gradle init file very easily.
Gradle init script provides same functionality as Maven super/parent pom. The basic difference is that you can call init script
Run time
As many as of them This gives us flexibility to change the init
script on run time but doubt of not tracking the changes.
You need to take repository, distribution management, profiling and other checks like findbugs, checkstyle etc in to init script.
The detail is huge, You can find complete information here by me.
http://www.scmtechblog.net/2015/12/how-to-migrate-parent-pom-from-maven-to.html
I have explained about gradle release plugin which is similar to maven release plugin.
to achive your goal you could apply the concept of 'multiproject build' explained in the gradel user guide here
Basically you can create an umbrella project which define a set of common configurations by creating a gradle.build file and a gradle.settings file.
The build file contains the properties, dependencies and plugins commons to all projects, the settings.gradle defines what subprojects inherits those configurations.
Moreover, to have an idea of the gradle plugin ecosystem you could check this source.
It is currently not possible, if you want the parent to be cached locally and stored in a Maven repository.
I have added feature request here:
http://forums.gradle.org/gradle/topics/support_for_gradle_parent_shared_between_projects_cached_locally

Gradle / Maven: How to use in-developement dependencies?

Context:
I'm working on a Gradle project which depends on external libraries, also created by me. Currently I was usign a simple dependecy on project(':lib').
But this is not enough anymore, I need to release and distribute libraries as standalone components, versionned and documented. I will install Apache Archiva and publish them to an internal maven repository, so I can depend explicitly on 'com.company:lib:1.0'.
Question:
During developement, I will work on libraries and on projects at the same time. How can I test my code without publishing the libraries ? My application which used to depend on project() will now depend on a specific version. But while developing, I would like to use the local code.
Do you know what is the best process to handle this ?
One way would be to add the dependency conditionally. So for your local builds (IDE) you want to build the dependency via source. Then you can distinguish your release builds by having your releases pass a param to a build.
dependencies {
if (project.hasProperty('release')) {
compile 'com.company:lib:1.0'
} else {
compile project(':lib')
}
}
Then in your release builds to use the lib from nexus:
$ gradle -Prelease=true clean build
If you want to build the project with the lib from inside the project:
$ gradle clean build
The correct answer to this question is available in Gradle's documentation (section 23.8.3.1), and is the following:
configurations.all {
resolutionStrategy.dependencySubstitution {
substitute module("com.company:lib") with project(":lib")
substitute module("com.company:lib2") with project(":lib2")
}
}
Personally, I used the following code, which makes all -SNAPSHOT versions to be taken from local projects instead of remote repository (if a local project is available):
configurations.all {
resolutionStrategy.dependencySubstitution {
all { dependency ->
if (! dependency.requested.version.endsWith('SNAPSHOT'))
return
if (subprojects.find { p ->p.name == dependency.requested.module })
dependency.useTarget project(":" + dependency.requested.module)
}
}
}

Categories