12

I'm trying to build a jar from a kotlin app using intelliJ idea, everything works from intellij, it's able to run kotlin files with the main method, however after building the jar with gradle jar I get:

java -cp build/libs/sensorPreprocessor-1.0-SNAPSHOT.jar co.myapp.sensorPreprocessor.MqttPollerKt
Error: Could not find or load main class co.myapp.sensorPreprocessor.MqttPollerKt

my build.gradle is this:



plugins {
    id 'org.jetbrains.kotlin.jvm' version '1.3.31'
    id "com.commercehub.gradle.plugin.avro" version '0.16.0'
}

apply plugin: 'kotlin'
apply plugin: 'application'
mainClassName = 'co.myapp.sensorPreprocessor.MqttPollerKt'

group 'co.myapp'
version '1.0-SNAPSHOT'

repositories {
    mavenCentral()
    jcenter()
    maven {
        url  "https://dl.bintray.com/cbeust/maven"
    }
    maven {
        url  "http://packages.confluent.io/maven/"
    }
}

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
    compile "org.jetbrains.kotlin:kotlin-reflect:1.3.31"
    testCompile group: 'junit', name: 'junit', version: '4.12'

    compile group: 'org.apache.kafka', name: 'kafka-streams', version: '2.2.0'
    compile group: 'com.igormaznitsa', name: 'jbbp', version: '1.4.1'
    compile group: 'software.amazon.awssdk', name: 'sqs', version: '2.5.45'
    compile group: 'com.amazonaws', name: 'aws-iot-device-sdk-java', version: '1.3.0'
    compile group: 'com.amazonaws', name: 'aws-iot-device-sdk-java-samples', version: '1.3.0'
    compile group: 'com.beust', name: 'klaxon', version: '5.0.5'
    compile group: 'org.apache.kafka', name: 'kafka-clients', version: '2.2.0'
    compile group: 'io.confluent', name: 'kafka-avro-serializer', version: '5.2.1'
    compile group: 'io.confluent', name: 'kafka-streams-avro-serde', version: '5.2.1'
    compile group: 'io.confluent', name: 'monitoring-interceptors', version: '5.2.1'
    compile group: 'org.apache.avro', name: 'avro', version: '1.9.0'
}

compileKotlin {
    kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
    kotlinOptions.jvmTarget = "1.8"
}

jar {
    manifest {
        attributes 'Main-Class': 'co.myapp.sensorPreprocessor.MqttPollerKt'
    }

    from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
}

my main file is this:

package co.myapp.sensorPreprocessor

import software.amazon.awssdk.services.sqs.model.Message as AwsSqsMessage
....


class MqttPoller {
    companion object {
        @JvmStatic fun main(args: Array<String>) {
            start()
        }

        fun start() {
            ...
        }
    }
}

class MessagesTopic(topic: String, qos: AWSIotQos, private val kafkaProducer: KafkaProducer<String, SensorData>) : AWSIotTopic(topic, qos) {
    override fun onMessage(message: AWSIotMessage?) {
        ....
    }
}


fun main() {
    MqttPoller.start()
}

I've tried both co.myapp.sensorPreprocessor.MqttPollerKt and co.myapp.sensorPreprocessor.MqttPoller with the same results. If after I type java -cp JAR_PATH <tab> I try to autocomplete I can see it autocompletes with my class names, but still it doesn't work.

If I try to use javap it also shows the class:

➜  iot-services-sensor-preprocessor git:(master) ✗ javap -cp build/libs/sensorPreprocessor-1.0-SNAPSHOT.jar co.myapp.sensorPreprocessor.MqttPollerKt
Compiled from "MqttPoller.kt"
public final class co.myapp.sensorPreprocessor.MqttPollerKt {
  public static final void main();
  public static void main(java.lang.String[]);
}
➜  iot-services-sensor-preprocessor git:(master) ✗ javap -verbose -cp build/libs/sensorPreprocessor-1.0-SNAPSHOT.jar co.myapp.sensorPreprocessor.MqttPollerKt
Classfile jar:file:///Users/alex/Projects/myapp/build/libs/sensorPreprocessor-1.0-SNAPSHOT.jar!/co/myapp/sensorPreprocessor/MqttPollerKt.class
  Last modified May 21, 2019; size 754 bytes
  MD5 checksum 52febc7a2f38ef786ded2198193827b3
  Compiled from "MqttPoller.kt"
public final class co.myapp.sensorPreprocessor.MqttPollerKt
  minor version: 0
  major version: 52
  flags: (0x0031) ACC_PUBLIC, ACC_FINAL, ACC_SUPER
  this_class: #2                          // co/myapp/sensorPreprocessor/MqttPollerKt
  super_class: #4                         // java/lang/Object
  interfaces: 0, fields: 0, methods: 2, attributes: 2
Constant pool:
   #1 = Utf8               co/myapp/sensorPreprocessor/MqttPollerKt
   #2 = Class              #1             // co/myapp/sensorPreprocessor/MqttPollerKt
   #3 = Utf8               java/lang/Object
   #4 = Class              #3             // java/lang/Object
   #5 = Utf8               main
   #6 = Utf8               ()V
   #7 = Utf8               ([Ljava/lang/String;)V
   #8 = NameAndType        #5:#6          // main:()V
   #9 = Methodref          #2.#8          // co/myapp/sensorPreprocessor/MqttPollerKt.main:()V
  #10 = Utf8               co/myapp/sensorPreprocessor/MqttPoller
  #11 = Class              #10            // co/myapp/sensorPreprocessor/MqttPoller
  #12 = Utf8               Companion
  #13 = Utf8               Lco/myapp/sensorPreprocessor/MqttPoller$Companion;
  #14 = NameAndType        #12:#13        // Companion:Lco/myapp/sensorPreprocessor/MqttPoller$Companion;
  #15 = Fieldref           #11.#14        // co/myapp/sensorPreprocessor/MqttPoller.Companion:Lco/myapp/sensorPreprocessor/MqttPoller$Companion;
  #16 = Utf8               co/myapp/sensorPreprocessor/MqttPoller$Companion
  #17 = Class              #16            // co/myapp/sensorPreprocessor/MqttPoller$Companion
  #18 = Utf8               start
  #19 = NameAndType        #18:#6         // start:()V
  #20 = Methodref          #17.#19        // co/myapp/sensorPreprocessor/MqttPoller$Companion.start:()V
  #21 = Utf8               Lkotlin/Metadata;
  #22 = Utf8               mv
  #23 = Integer            1
  #24 = Integer            15
  #25 = Utf8               bv
  #26 = Integer            0
  #27 = Integer            3
  #28 = Utf8               k
  #29 = Integer            2
  #30 = Utf8               d1
  #31 = Utf8               \u0000\b\n\u0000\n\u0002\u0010\u0002\n\u0000\u001a\u0006\u0010\u0000\u001a\u00020\u0001¨\u0006\u0002
  #32 = Utf8               d2
  #33 = Utf8
  #34 = Utf8               sensorPreprocessor
  #35 = Utf8               MqttPoller.kt
  #36 = Utf8               Code
  #37 = Utf8               LineNumberTable
  #38 = Utf8               SourceFile
  #39 = Utf8               RuntimeVisibleAnnotations
{
  public static final void main();
    descriptor: ()V
    flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
    Code:
      stack=1, locals=0, args_size=0
         0: getstatic     #15                 // Field co/myapp/sensorPreprocessor/MqttPoller.Companion:Lco/myapp/sensorPreprocessor/MqttPoller$Companion;
         3: invokevirtual #20                 // Method co/myapp/sensorPreprocessor/MqttPoller$Companion.start:()V
         6: return
      LineNumberTable:
        line 78: 0
        line 79: 6

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: (0x1009) ACC_PUBLIC, ACC_STATIC, ACC_SYNTHETIC
    Code:
      stack=0, locals=1, args_size=1
         0: invokestatic  #9                  // Method main:()V
         3: return
}
SourceFile: "MqttPoller.kt"
RuntimeVisibleAnnotations:
  0: #21(#22=[I#23,I#23,I#24],#25=[I#23,I#26,I#27],#28=I#29,#30=[s#31],#32=[s#5,s#33,s#34])
    kotlin.Metadata(
      mv=[1,1,15]
      bv=[1,0,3]
      k=2
      d1=["\u0000\b\n\u0000\n\u0002\u0010\u0002\n\u0000\u001a\u0006\u0010\u0000\u001a\u00020\u0001¨\u0006\u0002"]
      d2=["main","","sensorPreprocessor"]
    )
alex88
  • 4,788
  • 4
  • 39
  • 60
  • Try doing `ls build/libs/sensorPreprocessor-1.0-SNAPSHOT.jar`. Does the jar actually exist? Are you in the correct directory? Note that the `java` command doesn't complain about a non-existent jar as a `-cp` option parameter. – DodgyCodeException May 21 '19 at 14:45
  • I guess you have followed [this](https://kotlinlang.org/docs/reference/using-gradle.html) and checked that everything is exactly setup like it should be? – Lino May 21 '19 at 14:45
  • @DodgyCodeException yes, in fact I can also read the classes from that file – alex88 May 21 '19 at 14:50
  • @AshwanthKumar tried that now, same thing – alex88 May 21 '19 at 14:50
  • @Lino I've created the project with IntelliJ, I've tried to re-create and empty project and it seems that the `org.jetbrains.kotlin.jvm` plugin takes care of the gradle integration – alex88 May 21 '19 at 14:51
  • @Roland you mean adding `configurations.implementation.collect { it.isDirectory() ? it : zipTree(it) }` ? I've tried that but I get `Resolving configuration 'implementation' directly is not allowed`, is that what you meant? – alex88 May 21 '19 at 15:06
  • ... or just switch `implementation` to `compile` for that test... – Roland May 21 '19 at 15:07
  • @Roland just tried that, it takes more time to build the jar but it still fails with the same error – alex88 May 21 '19 at 15:11
  • 1
    I've solved it adding the gradle shadow plugin, would be nice to understand why it wasn't working before tho – alex88 May 21 '19 at 15:19
  • 1
    maybe you want to go through that list: https://stackoverflow.com/a/18093929/6202869 – Roland May 21 '19 at 15:19
  • @alex88 but that's not really solving this particular issue ;-) this is rather a workaround... but if it works.. ok... – Roland May 21 '19 at 15:20
  • @Roland I would love to know why it wasn't working, I've tried to start a new app, add a single dependency and the error was `Exception in thread "main" java.lang.NoClassDefFoundError: kotlin/jvm/internal/Intrinsics` but I think it's not the one i was facing, I think I wasn't doing one of these things listed here https://imperceptiblethoughts.com/shadow/getting-started/#default-java-groovy-tasks – alex88 May 21 '19 at 15:24
  • @Roland also, looking at your list, should the fact that `javap` shows the class and its main function mean that the classpath/name/package/folder is all correct? – alex88 May 21 '19 at 15:25
  • @alex88 yes... your bytecode looks good... also the path to `main` looks good... your statement regarding `NoClassDefFoundError ... Intrinsics` basically points to a missing `kotlin-stdlib`. – Roland May 21 '19 at 15:28
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/193714/discussion-between-roland-and-alex88). – Roland May 21 '19 at 15:31

1 Answers1

18

I've found the issue, in the jar task I had to add

exclude 'META-INF/*.RSA', 'META-INF/*.SF','META-INF/*.DSA'

so it becomes:

jar {
    manifest {
        attributes 'Main-Class': 'co.myapp.sensorPreprocessor.MqttPollerKt'
    }

    exclude 'META-INF/*.RSA', 'META-INF/*.SF','META-INF/*.DSA'

    from {
        (configurations.compile).collect {
            it.isDirectory() ? it : zipTree(it)
        }
    }
}
alex88
  • 4,788
  • 4
  • 39
  • 60