mm, ```Cannot access 'java.io.Serializable' which ...
# gradle
e
mm,
Copy code
Cannot access 'java.io.Serializable' which is a supertype of 'kotlin.String'. Check your module classpath for missing or conflicting dependencies
I have jvm module with kotlin plugin and std lib is added by default. What do I miss in my gradle?
1
Oke, I have to setup JDK in the project settings
c
Alternatively, you should use JVM toolchains to automatically setup the JDK for everyone opening the project: In your
settings.gradle.kts
add:
Copy code
plugins {
    id("org.gradle.toolchains.foojay-resolver-convention") version "0.7.0"
}
In all your
build.gradle.kts
files that have the Kotlin plugin, add:
Copy code
kotlin {
    jvmToolchain(17) // or any other version
}
This way, when you open the repository, Gradle will automatically download that version of the JDK and use it. It automatically sets
sourceCompatibility
etc.
1
e
Thanks!
m
I never really understood how IntelliJ was handling this: • JAVA_HOME • toolchain • options.release() What's important here is the
rt.jar
that is in the compileClasspath, right? I wish this could work without toolchains. I don't want to download N toolchains for N projects if I have Java 21 installed locally
👍 1
c
I'm not an expert at all, so this may be completely wrong, but this is my understanding: • when you run Gradle, it uses the ‘simplest’ accessible JVM to run itself. I think it searches from the PATH first, then JAVA_HOME, then gives up. • when you run a task that requires a JRE or JDK, by default Gradle uses the JVM it found to run itself, to run that. • if you specify a toolchain, it will use it instead to run the task. First, it scans through your entire system to find one that matches the version number (and other criteria) you requested. If it doesn't find any, then it gives up. The foojay plugin mentioned above configures Gradle to download it, instead of giving up—but it only does something when Gradle couldn't find anything. So, on the Gradle side, if you request a toolchain that is already installed on your system, Gradle should use that one, and install nothing more. However if you request one you do not have, and use the foojay plugin, it will download it to ~/.gradle/jdk. On IDEA's side: • IDEA comes with its own JDK, which is a fork of OpenJDK with a few edits made by JetBrains (IIRC it's mostly font-related). • when you configure a project, it lets you use any JDK available on your system, or download more. • if you sync a project that uses Gradle with toolchains, IDEA learns about them and configures itself to use the same ones as what Gradle uses.
So if you specify a JVM toolchain that you have already installed (either through your package manager, or through IDEA, or through SDKMAN, ...), both Gradle and IDEA should both use it automatically But if you clone a project that requires a JDK you don't have, then Gradle will download it, and IDEA will find it as well
Anyway the point is: the person who clones the project has no configuration required inside IDEA
m
But toolchain only feel like a band aid because some tasks (
compileJava
, others?) depend on the JDK version when it really should not be the case. Whether I run my Java8 bytecode on JDK8 or JDK21 should be irrelevant I think?
c
Bytecode yes, but the standard library is different.
m
there is
options.release()
for that I think?
Ideally IDEA can introspect that and download the "good"
rt.jar
without downloading all of the JDK, like it's doing for
kotlin-stdlib
c
What do you do if you want to run a project that just cannot run in Java 9+ because of jigsaw? You can tell the compiler anything you want about bytecode, it just won't run 😅
🤔 1
m
Jigsaw is the module system, right?
👍 1
Then I guess in that case I'm screwed indeed. But I'm probably going to open an issue on that project to have support for newer JDKs
c
We have legacy projects where that just will not happen 😅
m
Hot take: Setting a toolchain shuold be the last thing to do before archiving a project 😄
c
Toolchains are great because you can side-step all of this entirely. Just run it with whatever lowest JVM you want to release for, and everything else (including source compatibility, IDE settings, etc) is automatically taken care of for you. Of course, the downside is it needs to install that JVM, but you probably already have it.
I have JDK 17+ projects, and I have contributors that only have JDK 8/11 installed on their machine, each time I have to explain to them in issues that they must configure JDK 17 in the IDEA, etc. Now, I don't. They clone the repo, they get the correct JDK.
m
Fair enough
I wish gradle would have its own bootsrap (and that bootstrap be able to specify either an exact or minimum version)
We'll get there one day
c
Well... That's exactly what this feature is, isn't it?
m
Except toolchains are "exact"
I wish there were more like "minimum version"
e
I think the orinal issue was - I'm not a java developer and I usually care about installed jdk numbered times a year. I cloned project, opened it in Fleet, got bitten, opened it in IDEA (that I use numbered times a year). And assumed that things should just work :).
c
Well, with toolchains you're guaranteed the entire team uses the same JDK.
e
The docker images are taking care of the cu build reproducibility. And Kotlin covers jdk versions. In addition android is my runtime.
c
Also, if you have different modules that require different JDKs, in the same repo (we do), good luck making that work without setting the toolchains.
m
That's exactly my point actually. By using toolchains, we reinforce the belief that every one must use the same JDK while I don't think there's a strong use case for that besides the legacy projects you mentioned
Why is the java version an input to
compileJava
? I have no clue
c
I don't recommend Gradle in Docker. Almost everything in Gradle is meant for stateful builds, by using containers you lose that (except through something like devcontainers, which are stateful)
e
Not sure I understood
c
strong use case for that besides the legacy projects
And the opposite: projects that require a min JDK higher than what the user has.
👍 1
If you start a container each time you run Gradle, you lose caching, daemon startup times, JVM warmup times, etc
m
> projects that require a min JDK higher than what the user has. Indeed, that's where a "minimum version if not download" (instead of "exact match") is useful
e
Caching is preserved by cache server or storing.restorung cache and the rest is neglectable for our ci builds
c
I think having minimum versions in toolchains is something they could implement. After all, what they do is search for a compatible toolchain, they can implement that how they want. Maybe worth a feature request.
👍 1
Sorry, I wasn't clear. Running Gradle in containers for CI is also how I do it. I thought you meant containers for local development (what the issue linked previously was about)
👍 1