https://kotlinlang.org logo
Title
e

Emil Kantis

02/27/2023, 8:26 AM
Tried to pen something about using Kotlin + Gradle (starting from a Spring initializr template). Happy to receive feedback on it 🙂 https://kantis.github.io/posts/gradle/
v

Vampire

02/27/2023, 8:41 AM
I just very roughly skimmed over the code examples: • do not use the Spring dependency management plugin, it is a relict from times when Gradle had no built-in BOM support. Even the maintainer of that plugin recommends to use the built-in BOM support instead • Consider using Kotlin 1.8.10, not 1.7, then you have proper toolchain support and do not need to with with
...Compatibility
, and you can use the new lazy-enabled
compileOptions
instead of the eager
kotlinOptions
. • Better not set the free compiler args unless you really want to overwrite all existing values but instead add to them • When adding authenticated repository you might consider using the Gradle credentials support, so that you don't have the credentials in pain text in the build script
e

Emil Kantis

02/27/2023, 9:14 AM
Will update the article tonight, thanks Björn 🙂
Added a new article where I address the things you mentioned instead (original articles goal was to break down what the content generated by start.spring.io was) 🙂 https://kantis.github.io/posts/gradle-improvements/
If you want me to remove your name, or link to you somehow, let me know
h

Humphrey

03/13/2023, 1:22 AM
Love this article! Now waiting for the multi module one. I’ve one working with spring boot where the root project is like a holder for the sub projects, and I use spring boot dependencyManagement to configure all dependency versions in the sub projects.
v

Vampire

03/13/2023, 1:26 AM
You've read that above I wrote that even the author of the Spring dependency managament plugin recommends not to use it? 😉
h

Humphrey

03/13/2023, 8:32 AM
The build in BOM support, that is for the dependency management right? By using Imports { mavenBom(SpringBootPlugin.BOM_COORDINATES) } In the dependencyManagement block?!
v

Vampire

03/13/2023, 8:33 AM
That is the spring dependency management you shouldn't use anymore. The built-in is the one with
platform(...)
.
h

Humphrey

03/13/2023, 8:36 AM
I’ll take a look at it, do you have a link to documentation?
e

Emil Kantis

03/13/2023, 8:38 AM
The follow-up article included how to use the BOM 🙂 https://kantis.github.io/posts/gradle-improvements/
and thanks for the feedback, gives me some extra energy to get working on the multi-module article 😄
h

Humphrey

03/13/2023, 8:44 AM
I've the following settings:
plugins {
    id("org.springframework.boot") version "3.0.4" apply false
    id("io.spring.dependency-management") version "1.1.0"
    kotlin("jvm") version "1.8.0" apply false
    kotlin("plugin.spring") version "1.8.0" apply false
}

subprojects {

    plugins.apply("java-library")
    plugins.apply("org.jetbrains.kotlin.jvm")
    plugins.apply("org.jetbrains.kotlin.plugin.spring")
    plugins.apply("io.spring.dependency-management")

    dependencyManagement {
        imports {
            mavenBom(SpringBootPlugin.BOM_COORDINATES)
        }
    }

    dependencies{
        implementation()
    }
}
But then I don't get implementation, it will be marked in red. But dependencyManagement works...
v

Vampire

03/13/2023, 8:48 AM
Don't use
subprojects { ... }
, it is bad practice and has several drawbacks. Use convention plugins to share build configuration. You only get type-safe accessors like
implementation
when you apply plugins priority using the
plugins { ... }
block. If you insist on following the bad practice you could use
"implementation"(...)
instead.
h

Humphrey

03/13/2023, 10:06 AM
Sorry was in a meeting, but I would like to have the root project to be a kind of holder for the subprojects. One sub-project could be like a library with domain objects pojo and do not need Spring Boot dependency, and another subproject is importing the first one and adding Spring Boot functionality to it. And maybe another project is doing something completely different. How to achieve that? I would like to manage all dependencies (and versions) from one place (project root).
v

Vampire

03/13/2023, 11:15 AM
You shouldn't. To manage versions in one place, I'd recommend to use a version catalog. For the build logic you want to share, you should create convention plugins, e.g. in
buildSrc
or an included build, and then apply those convention plugins directly in the projects where you want these conventions to be in effect. If you e.g. have 5 projects, where 3 are Java libraries and 2 are Java applications, you could e.g. have two convention plugins, one with the settings you want in Java library projects and one with the settings you want in Java application projects and then you apply the respecitve convention plugin in the respective projects directly. Using
allprojects { ... }
or
subprojects { ... }
is so-called cross-project configuration which introduces project coupling which works against more sophisticated features like configure-on-demand or configuration cache, or project isolation, ... And besides that it makes builds harder to understand and harder to maintain, as project's build script is not the source of truth, but you have to know and check places where you inject settings from outside.
h

Humphrey

03/13/2023, 11:22 AM
How would my root project look like? Which plugins should be applied there? Like I would only want to have spring boot applied to the two applications sub projects and not to the other 3 libraries from your example.
e

Emil Kantis

03/13/2023, 11:30 AM
My root project typically only contains report aggregation tasks and the like. Your application convention plugin would apply the Spring Boot plugin, while your library conventions wouldn't
h

Humphrey

03/13/2023, 11:43 AM
Looks very complicated setup. Subproject pointing back to ../../gradle/settings folder.
v

Vampire

03/13/2023, 11:44 AM
You probably don't need all from there. Just an example where you could look or watch the video of Jendrik. 🙂
e

Emil Kantis

03/13/2023, 11:45 AM
Johannes also puts convention plugins in
./gradle/plugins
, how does that compare to using
buildSrc
or an included build?
h

Humphrey

03/13/2023, 12:20 PM
Which video from Jendrik?
v

Vampire

03/13/2023, 12:20 PM
It is linked in the description of that repository. He often makes pretty popular YT videos explaining Gradle features.
h

Humphrey

03/13/2023, 12:23 PM
v

Vampire

03/13/2023, 12:26 PM
Johannes
Jendrik. Johannes is the last name. 😄 (I made that error myself too)
also puts convention plugins in
./gradle/plugins
, how does that compare to using
buildSrc
or an included build?
I usually put them in
./gradle/build-logic
. Comparing to "an included build" is hard, because it most probably IS an included build.
buildSrc
vs. an included build is in the meantime for the most part a philosophical question. Since Gradle 8,
buildSrc
changed in some aspects to be even more similar to an included build. But I personally still prefer included builds. The most significant difference comes into play if you have several different convention plugins that are not applied everywhere. If you have those in an included build in multiple projects in that build (or in multiple included builds), then only projects that use them get their classpath changed on a change in the plugin and thus only those need to be re-executed.
buildSrc
result is prepended to all build script classpaths and thus every change invalidates everything. In small projects or if you only have convention plugins you anyway apply everwhere or almost everywhere, this difference is usually neglectible. Another difference is, that with
buildSrc
you get type-safe accessors for the plugins for usage in Kotlin DSL, while coming from an included build (except when using a little hack) you have to use their ID to apply them, which I don't see as major drawback. You can also add them to a version catalog and use it from there. Another difference where you must use
buildSrc
due to the classpath prepending is, if you have the rare need to monkey-patch a plugin class. This only works when doing it in
buildSrc
, but I'm not going to elaborate on that here as you hopefully never need that.