vertx-lang-kotlin
vertx-lang-kotlin copied to clipboard
Kotlin Launcher sub-class does not function as expected
Sub-classing the Launcher in Kotlin produces a fat jar that does not run with any commands:
Usage: java -jar build/libs/kotlin-launcher-bug-1.0-SNAPSHOT-fat.jar [COMMAND] [OPTIONS] [arg...]
Commands:
bare Creates a bare instance of vert.x.
list List vert.x applications
run Runs a verticle called <main-verticle> in its own instance of
vert.x.
start Start a vert.x application in background
stop Stop a vert.x application
version Displays the version.
Run 'java -jar build/libs/kotlin-launcher-bug-1.0-SNAPSHOT-fat.jar COMMAND
--help' for more information on a command.
To reproduce this, compare the master branch of this project (an alternative Launcher written in Java):
> ./gradlew shadowJar
Deprecated Gradle features were used in this build, making it incompatible with Gradle 5.0.
See https://docs.gradle.org/4.5.1/userguide/command_line_interface.html#sec:command_line_warnings
BUILD SUCCESSFUL in 1s
2 actionable tasks: 2 executed
> java -jar build/libs/kotlin-launcher-bug-1.0-SNAPSHOT-fat.jar
Sep 30, 2018 12:26:41 AM io.vertx.starter.Launcher
INFO: Hello, Vert.x Launcher!
Sep 30, 2018 12:26:41 AM io.vertx.core.impl.launcher.commands.VertxIsolatedDeployer
INFO: Succeeded in deploying verticle
With the kotlin-launcher-bug branch:
> ./gradlew shadowJar
w: /home/user/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-jre7/1.2.20/.../kotlin-stdlib-jre7-1.2.20.jar: kotlin-stdlib-jre7 is deprecated. Please use kotlin-stdlib-jdk7 instead
w: /home/user/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-jre8/1.2.20/.../kotlin-stdlib-jre8-1.2.20.jar: kotlin-stdlib-jre8 is deprecated. Please use kotlin-stdlib-jdk8 instead
Deprecated Gradle features were used in this build, making it incompatible with Gradle 5.0.
See https://docs.gradle.org/4.5.1/userguide/command_line_interface.html#sec:command_line_warnings
BUILD SUCCESSFUL in 1s
3 actionable tasks: 3 executed
> java -jar build/libs/kotlin-launcher-bug-1.0-SNAPSHOT-fat.jar
Usage: java -jar build/libs/kotlin-launcher-bug-1.0-SNAPSHOT-fat.jar [COMMAND]
[OPTIONS] [arg...]
...etc
(I did some debugging but was not able to determine the issue, however, it is entirely possible that I am just dense.)
This works for me. I think your problem is this line in your gradle file: def mainVerticleName = 'io.vertx.starter.MainVerticle'
Because Kotlin it should be def mainVerticleName = 'io.vertx.starter.MainVerticleKt'
See my project as an example if you still have problems
https://github.com/lfmunoz/vertx-kt-rocket/blob/master/src/main/kotlin/com/lfmunoz/App.kt
I ran into the same issue and finally got it working:
This is my starter:
class Starter : VertxCommandLauncher(), VertxLifecycleHooks {
companion object {
@JvmStatic
fun main(vararg args: String) {
Starter().dispatch(args)
}
}
//implement empty interface methods here
Note that it must not extend from io.vertx.core.Launcher
due to signature clashes with fun main
.
Also, I used the "Main-Class" manifest entry (as opposed to "Launcher-Class"):
shadowJar {
archiveClassifier = 'fat'
manifest {
attributes('Main-Verticle': mainVerticle, 'Main-Class': mainClass, 'Commit': grgit.head().id)
}
}
(I did some debugging but was not able to determine the issue, however, it is entirely possible that I am just dense.)
I ran into the same issue and found the cause.
Take the following custom launcher, CustomLauncher.kt
:
import io.vertx.core.Launcher
fun main(vararg args: String) {
CustomLauncher().dispatch(args)
}
class CustomLauncher : Launcher() {
init {
println("Custom launcher")
}
}
This results in the following Java equivalent code:
public final class CustomLauncherKt {
public static final void main(String... args) {
(new CustomLauncher()).dispatch(args);
}
}
import io.vertx.core.Launcher;
public final class CustomLauncher extends Launcher {
public CustomLauncher() {
System.out.println("Custom launcher");
}
}
You can see this generates 2 classes, CustomLauncherKt
containing the main method and the Launcher
subclass called CustomLauncher
.
However, the VertxCommandLauncher.getCommandFromManifest()
method does the following (simplified for brevity):
String mainClass = attributes.getValue("Main-Class");
if (main != null && main.getClass().getName().equals(mainClass)) {
return attributes.getValue("Main-Verticle");
}
return null;
In this snippet, main
is the instance of your Launcher
subclass (so CustomLauncher
, in this case). But the Main-Class
entry in the manifest contains the class with the main method, so that would be CustomLauncherKt
. And CustomLauncher != CustomLauncherKt
, so instead of returning your main verticle it just returns null.
The getCommandFromManifest()
method assumes the main method is in your Launcher
subclass, which isn't Kotlin friendly.
Is there any update on this? I'm currently doing what @michaelom does and just creating my own launcher class...that seems to be the best solution at the moment
@nicksc423 doing the same and don't know about any other solution so far.
Updating's @dvdmunckhof solution:
import io.vertx.core.Launcher
fun main(vararg args: String) {
val launcher = CustomLauncher()
launcher.dispatch(launcher, args) // call the dispatch(main, args) method
}
class CustomLauncher : Launcher() {
init {
println("Custom launcher")
}
}