Running Javalin with JPMS and ServiceLoader leads to a NoClassDefFoundError: kotlin/NoWhenBranchMatchedException
. The same code following two other approaches works fine, though (see at the end of this post for details):
No JPMS and ServiceLoader: if I run the very same Javalin application not as a JPMS module and without the ServiceLoader to resolve dependencies, then everything works just fine.
Console app: I can also run a console application which is a real JPMS module and uses the ServiceLoader to resolve dependencies.
(1) Clone main branch
(2) Try to run API in root folder of project
# Windows
.\gradlew.bat :api:run
# Linux
./gradlew :api:run
You should see the following error:
> Task :api:run FAILED
[main] INFO org.example.api.WebAPI - Hello World from WebAPI, yay :-)
Exception in thread "main" java.lang.NoClassDefFoundError: kotlin/NoWhenBranchMatchedException
at io.javalin@4.6.4/io.javalin.core.JavalinConfig$Inner.<init>(JavalinConfig.java:77)
at io.javalin@4.6.4/io.javalin.core.JavalinConfig.<init>(JavalinConfig.java:67)
at io.javalin@4.6.4/io.javalin.Javalin.<init>(Javalin.java:54)
at io.javalin@4.6.4/io.javalin.Javalin.create(Javalin.java:91)
at io.javalin@4.6.4/io.javalin.Javalin.create(Javalin.java:78)
at org.example.api/org.example.api.WebAPI.main(WebAPI.java:24)
Caused by: java.lang.ClassNotFoundException: kotlin.NoWhenBranchMatchedException
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
... 6 more
FAILURE: Build failed with an exception.
(3) No JPMS and ServiceLoader: change to branch no-jpms-and-serviceloader and then you can successfully run the API via
# Windows
.\gradlew.bat :api:run
# Linux
./gradlew :api:run
(4) Console app: run it as a console application in either of the branches
# Windows
.\gradlew.bat :client:run
# Linux
./gradlew :client:run
I've created a Javalin GitHub issue describing the same issue. It's solved by now, but for convenience reasons I'll drop the solution here on Stackoverflow as well.
Adding the following line to the module descriptor (module-info.java
) of the api
project solves the issue:
requires io.javalin;
requires com.fasterxml.jackson.databind;
requires org.slf4j.simple;
requires kotlin.stdlib; <-- simply add this line here
uses org.example.services.api.PersonReader;
The root cause seems to be that Javalin is not modularized yet. If you look closer into the module resolution (pass --show-module-resolution
arg to java) you will see that Javalin is treated as an automatic module and the auto-generated requires statements for this automatic module do not include kotlin.stdlib
.
If Javalin ever becomes modularized this should no longer be an issue. Until then, this is a viable solution which can also be applied to other not-yet-modularized projects.