I understand there is library dependency management in Springboot so that the correct version of starter kits will be picked for the Springboot version. However I do not fully understand how the third-party libs' versions are controlled.
For example, in build.gradle file, we can use a lib like this:
implementation('org.liquibase:liquibase-core') .
I know that Gradle's logic is to pick the latest version if no version is specified. I am not sure if there are any tools like a lock file to lock down ALL the versions used by this application, or we have to specify the version like:
compileOnly 'org.projectlombok:lombok:1.18.4' ?
So that we can be confident that all the libs used in the team are identical.
The best practice recommended by gradle is to declare dependencies without versions and use dependency constraints.
dependencies {
implementation 'org.liquibase:liquibase-core'
}
dependencies {
constraints {
implementation 'org.liquibase:liquibase-core:3.6.2'
}
}
Related
I have a collection of related Gradle projects, not all of them in the same repository (hence not sharing the same gradle.properties or settings.gradle.kts files).
My objective is having my main build scripts (build.gradle.kts files) completely clean from dependency version numbers and at the same time avoiding to specify the same version number in more than once settings or properties file.
I am looking for the best practices to accomplish this, taking into consideration that these version numbers can appear both in Gradle dependencies or plugin declarations and often need to be kept in sync between them.
As a use case, lets configure projects that require spring boot.
In this case, I can use a Gradle platform project to define common dependency versions. As an example, the build.gradle.ktsof my platform project looks a bit like this:
plugins {
`java-platform`
}
javaPlatform {
allowDependencies()
}
dependencies {
api(platform("org.springframework.boot:spring-boot-dependencies:2.3.0.RELEASE"))
constraints {
api("io.mockk:mockk:1.10.0")
api("org.junit.jupiter:junit-jupiter:5.6.2")
api("io.kotest:kotest-runner-junit5-jvm:4.0.6")
...
}
}
So I am conveniently specifying all the spring boot dependencies + my own dependencies in one single platform project.
But other projects which use spring boot dependencies also require the org.springframework.boot plugin, where its version should better be the same than the spring boot dependency required in the platform project.
As said at the beginning, those projects are located in other repositories, hence they do not share the same configuration files as the platform project.
In those projects I am adding in their settings.gradle.kts file the following block:
pluginManagement {
plugins {
id("org.springframework.boot").version("2.3.0.RELEASE")
...
}
}
It works, since after importing the platform project I can keep my main build file clean from version numbers, as intended (neither the spring boot dependencies nor the spring boot plugin itself will require anymore to specify their versions).
However, this just does not feel good. Now I have the same version of spring boot (2.3.0.RELEASE) hard-coded in both my platform project and in the settings file of the project using the Spring boot plugin. Now I have the problem of keeping both numbers, located in distinct projects, synchronized.
Which is the "correct" Gradle way to solve this? Is there a way to make a Gradle platform project to also specify plugin version numbers in a similar way preferred dependency versions can be declared there?
Imagine there is a Gradle project with 2 modules, modA and modB. modB depends on modA.
// within modB's build.gradle
dependencies {
implementation 'com.example:modA:x.y.z'
}
I could also define the top level's project dependencies like this:
// within the top level build.gradle
project(':modB') {
dependencies {
implementation project(':modA')
}
}
In this latter example, the output from modA's compilation is put on the classpath for the compilation of modB.
What happens if I use both in the same project: what version of classes will get compiled into modB? Will it be version x.y.z of modA, or will it be the versions that have just been compiled?
I'm trying to work out a sensible way of versioning a monorepo's submodules, where each submodule needs to have a separate version and I'm wanting to understand how Gradle resolves versions.
These notations are different:
First asks gradle to go to the repository (public or local, it depends on main gradle file) and get jar from there. In this case mobB and mobA are fully independent, so they could be built in parallel.
Second asks gradle to use local project. It means that mobB requires compilation of mobA, etc.
For complex multiproject, please also consider Spring Dependency Management plugin. It allows you to define complex rules at the one include script. For example, you can put logice like this "if project is external client then exclude the following". As a result, you can consolidate all dependencies and versions at the one script, so your project will contain nothing.
I've created new Kotlin project under Gradle. By default it sets this dependencies to the Kotlin-library project. And I wonder what does this kotlin-bom lib do ?
dependencies {
// Align versions of all Kotlin components
implementation(platform("org.jetbrains.kotlin:kotlin-bom"))
// Use the Kotlin JDK 8 standard library.
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
// Use the Kotlin test library.
testImplementation("org.jetbrains.kotlin:kotlin-test")
// Use the Kotlin JUnit integration.
testImplementation("org.jetbrains.kotlin:kotlin-test-junit")
}
The kotlin-bom artifact is a dependency-only POM that aligns all the Kotlin SDK libraries with the same version.
See the POM content for version 1.5.31 for an example. It uses the POM's dependencyManagement section to depend on the same version of all the Kotlin SDK artifacts, like kotlin-stdlib, kotlin-stdlib-jdk8, kotlin-reflect, kotlin-test, etc.
Description of a BOM:
Software bill of materials (BOMs) don’t specify a dependency on a
module or file, but instead are a list of version constraints for
other components. They define what is called a platform, which is
basically a list of components with specific versions that are known
to play well together and/or form a useful unit of functionality. It’s
worth mentioning that not all of the dependencies listed in the BOM
actually have to be included in your projects — it’s basically a way
of saying “If you use any of these modules, use this version”.
-- A deep dive into an initial Kotlin build.gradle.kts
I have two Android apps that share a subproject. The build.gradle in the subproject contains a dependency like this:
dependencies {
compile "my.library.dependency:${version}"
}
What I'd like is to use this dependency at compile time, but not runtime. This is because the two apps need to link against slightly different versions of the dependency (same API).
The Gradle docs describe dependency configurations like this:
compile The dependencies required to compile the production source of
the project.
runtime The dependencies required by the production classes at
runtime. By default, also includes the compile time dependencies.
If runtime also includes compile dependencies, does this mean the library is exported from the subproject to the parent projects (and included in my apk)? If so, how do I prevent this? I assume it's possible because it says "by default".
Thanks in advance...
It's not clear if your subproject is using the android-library plugin, but if it is, v0.8 has added a provided scope -- see http://tools.android.com/recent/androidstudio043released.
This should work:
dependencies {
provided "my.library.dependency:${version}"
}
If you upgrade to 0.8 of the plugin, you'll need to run Gradle 1.10 (update gradle-wrapper.properties if you're using the wrapper), and if you're using Android Studio, upgrade to 0.4.3.
I currently have a project that I have performed an aqua scan on, and it identified the jackson-databind-2.9.8.jar I'm currently using as a critical vulnerability, and has recommended me to replace with version 2.10. To update this, while ensuring all other dependencies/code works fine, I've tried the following code in my build.gradle file, where group_name:microservice-event:0.2.+ shows up on the list of gradle dependencies and apparently brings in the 2.9.8 jar that is causing problems:
implementation 'com.fasterxml.jackson.core:jackson-databind:2.10'
implementation('*group_name*:microservice-event:0.2.+') {
exclude group: 'com.fasterxml.jackson.core', module: 'jackson-databind'
}
I've also removed the implementation '*group_name*:microservice-event:0.2.+' line I previously had in my build.gradle file.
However, now the project fails to build and I have no idea why. Would anyone know of how to write code in the build.gradle file to successfully exclude old jars/dependencies, while allowing for newer jars (as I've tried to do with the line implementation 'com.fasterxml.jackson.core:jackson-databind:2.10'). Note that I do not want to update the spring boot version.
When Gradle encounters two different versions of the same dependency, it will perform a conflict resolution. It defaults to choosing the highest version number.
However, because many libraries like Jackson consists of a number of individual modules like jackson-databind and jackson-core, you may end up in a situation where there is a mismatch between the different versions.
To align them, you can use the Jackson BOM and Gradle's platform dependency mechanism. It looks like this (choose only one of the depencendies below):
dependencies {
// Enforce the specified version
implementation(enforcedPlatform("com.fasterxml.jackson:jackson-bom:2.10.4"))
// Align all modules to the same version, but allow upgrade to a higher version
implementation(platform("com.fasterxml.jackson:jackson-bom:2.10.4"))
}
You don't need to exclude anything from your other dependencies.
If you encounter problems with the use of Jackson after upgrading, you should have a look at the release notes for 2.10 and check if you might be hit by any of the compatibility changes. Of cause, if the problem is in a third-party library, it might be more difficult to fix. But you may try the latest version in the 2.9 line (which is 2.9.10 at this time) and see if the vulnerability is fixed here.