From 2846cd224cf1c9a3d4e1273b69ce549041f367c7 Mon Sep 17 00:00:00 2001
From: Georgios Andrianakis <geoand@gmail.com>
Date: Thu, 8 Dec 2022 13:37:37 +0200
Subject: [PATCH] Fix combination of @QuarkusMain and Kotlin native application

Fixes: #29754
---
 .../quarkus/deployment/steps/KotlinUtil.java  | 16 +++++++++++++++
 .../deployment/steps/MainClassBuildStep.java  | 20 +++++++++++++++++--
 .../steps/RegisterForReflectionBuildStep.java |  8 ++------
 .../quarkus/it/kotser/GreetingApplication.kt  | 11 ++++++++++
 .../reactive/kotlin/GreetingApplication.kt    | 15 ++++++++++++++
 5 files changed, 62 insertions(+), 8 deletions(-)
 create mode 100644 core/deployment/src/main/java/io/quarkus/deployment/steps/KotlinUtil.java
 create mode 100644 integration-tests/kotlin-serialization/src/main/kotlin/io/quarkus/it/kotser/GreetingApplication.kt
 create mode 100644 integration-tests/resteasy-reactive-kotlin/standard/src/main/kotlin/io/quarkus/it/resteasy/reactive/kotlin/GreetingApplication.kt

diff --git a/core/deployment/src/main/java/io/quarkus/deployment/steps/KotlinUtil.java b/core/deployment/src/main/java/io/quarkus/deployment/steps/KotlinUtil.java
new file mode 100644
index 0000000000000..af69aa5390ac7
--- /dev/null
+++ b/core/deployment/src/main/java/io/quarkus/deployment/steps/KotlinUtil.java
@@ -0,0 +1,16 @@
+package io.quarkus.deployment.steps;
+
+import org.jboss.jandex.ClassInfo;
+import org.jboss.jandex.DotName;
+
+final class KotlinUtil {
+
+    private static final DotName KOTLIN_METADATA_ANNOTATION = DotName.createSimple("kotlin.Metadata");
+
+    private KotlinUtil() {
+    }
+
+    static boolean isKotlinClass(ClassInfo classInfo) {
+        return classInfo.hasDeclaredAnnotation(KOTLIN_METADATA_ANNOTATION);
+    }
+}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/steps/MainClassBuildStep.java b/core/deployment/src/main/java/io/quarkus/deployment/steps/MainClassBuildStep.java
index 6371b57ef3c7c..cfefd34f70fa4 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/steps/MainClassBuildStep.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/steps/MainClassBuildStep.java
@@ -1,5 +1,6 @@
 package io.quarkus.deployment.steps;
 
+import static io.quarkus.deployment.steps.KotlinUtil.isKotlinClass;
 import static io.quarkus.gizmo.MethodDescriptor.ofConstructor;
 import static io.quarkus.gizmo.MethodDescriptor.ofMethod;
 
@@ -17,6 +18,7 @@
 
 import org.jboss.jandex.AnnotationInstance;
 import org.jboss.jandex.AnnotationValue;
+import org.jboss.jandex.ArrayType;
 import org.jboss.jandex.ClassInfo;
 import org.jboss.jandex.DotName;
 import org.jboss.jandex.MethodInfo;
@@ -341,12 +343,13 @@ public MainClassBuildItem mainClassBuildStep(BuildProducer<GeneratedClassBuildIt
             if (nameValue != null) {
                 name = nameValue.asString();
             }
+            ClassInfo classInfo = i.target().asClass();
             if (quarkusMainAnnotations.containsKey(name)) {
                 throw new RuntimeException(
                         "More than one @QuarkusMain method found with name '" + name + "': "
-                                + i.target().asClass().name() + " and " + quarkusMainAnnotations.get(name));
+                                + classInfo.name() + " and " + quarkusMainAnnotations.get(name));
             }
-            quarkusMainAnnotations.put(name, i.target().asClass().name().toString());
+            quarkusMainAnnotations.put(name, sanitizeMainClassName(classInfo));
         }
 
         if (packageConfig.mainClass.isPresent()) {
@@ -410,6 +413,19 @@ public MainClassBuildItem mainClassBuildStep(BuildProducer<GeneratedClassBuildIt
         return new MainClassBuildItem(mainClassName);
     }
 
+    private static String sanitizeMainClassName(ClassInfo mainClass) {
+        String className = mainClass.name().toString();
+        if (isKotlinClass(mainClass)) {
+            MethodInfo mainMethod = mainClass.method("main",
+                    ArrayType.create(Type.create(DotName.createSimple(String.class.getName()), Type.Kind.CLASS), 1));
+            if (mainMethod == null) {
+                className += "Kt";
+            }
+
+        }
+        return className;
+    }
+
     private void generateMainForQuarkusApplication(String quarkusApplicationClassName,
             BuildProducer<GeneratedClassBuildItem> generatedClass) {
         ClassCreator file = new ClassCreator(new GeneratedClassGizmoAdaptor(generatedClass, true), MAIN_CLASS, null,
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/steps/RegisterForReflectionBuildStep.java b/core/deployment/src/main/java/io/quarkus/deployment/steps/RegisterForReflectionBuildStep.java
index 0018217fa3ae7..b4a085c479f28 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/steps/RegisterForReflectionBuildStep.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/steps/RegisterForReflectionBuildStep.java
@@ -1,5 +1,7 @@
 package io.quarkus.deployment.steps;
 
+import static io.quarkus.deployment.steps.KotlinUtil.isKotlinClass;
+
 import java.io.IOException;
 import java.lang.reflect.Modifier;
 import java.util.HashSet;
@@ -34,8 +36,6 @@ public class RegisterForReflectionBuildStep {
 
     private static final Logger log = Logger.getLogger(RegisterForReflectionBuildStep.class);
 
-    private static final DotName KOTLIN_METADATA_ANNOTATION = DotName.createSimple("kotlin.Metadata");
-
     @BuildStep
     public void build(CombinedIndexBuildItem combinedIndexBuildItem, Capabilities capabilities,
             BuildProducer<ReflectiveClassBuildItem> reflectiveClass,
@@ -98,10 +98,6 @@ public void build(CombinedIndexBuildItem combinedIndexBuildItem, Capabilities ca
         }
     }
 
-    private static boolean isKotlinClass(ClassInfo classInfo) {
-        return classInfo.hasDeclaredAnnotation(KOTLIN_METADATA_ANNOTATION);
-    }
-
     /**
      * BFS Recursive Method to register a class and it's inner classes for Reflection.
      *
diff --git a/integration-tests/kotlin-serialization/src/main/kotlin/io/quarkus/it/kotser/GreetingApplication.kt b/integration-tests/kotlin-serialization/src/main/kotlin/io/quarkus/it/kotser/GreetingApplication.kt
new file mode 100644
index 0000000000000..e7bd494373b0f
--- /dev/null
+++ b/integration-tests/kotlin-serialization/src/main/kotlin/io/quarkus/it/kotser/GreetingApplication.kt
@@ -0,0 +1,11 @@
+package io.quarkus.it.kotser
+
+import io.quarkus.runtime.Quarkus.run
+import io.quarkus.runtime.annotations.QuarkusMain
+
+@QuarkusMain
+class GreetingApplication
+
+fun main(args: Array<String>) {
+    run(*args)
+}
diff --git a/integration-tests/resteasy-reactive-kotlin/standard/src/main/kotlin/io/quarkus/it/resteasy/reactive/kotlin/GreetingApplication.kt b/integration-tests/resteasy-reactive-kotlin/standard/src/main/kotlin/io/quarkus/it/resteasy/reactive/kotlin/GreetingApplication.kt
new file mode 100644
index 0000000000000..1b18c62d2a3d4
--- /dev/null
+++ b/integration-tests/resteasy-reactive-kotlin/standard/src/main/kotlin/io/quarkus/it/resteasy/reactive/kotlin/GreetingApplication.kt
@@ -0,0 +1,15 @@
+package io.quarkus.it.resteasy.reactive.kotlin
+
+import io.quarkus.runtime.Quarkus.run
+import io.quarkus.runtime.annotations.QuarkusMain
+
+@QuarkusMain
+class GreetingApplication {
+
+    companion object {
+        @JvmStatic
+        fun main(args: Array<String>) {
+            run(*args)
+        }
+    }
+}