Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ClassNotFoundException for mixed java and kotlin code when running from command line

I have mixed Java & Kotlin code in a demo project which I want to run from command line. For only java, I am able to run the program with java -jar foo.jar but when I use any class from Kotlin code, it generates java.lang.NoClassDefFoundError: kotlin/jvm/internal/Intrinsics

I have tried different solutions and checked the jar file. It contains both the classes but I guess kotlin-runtime is missing from jar.

Here is build.gradle file

plugins {
    id 'java-library'
    id 'org.jetbrains.kotlin.jvm'
}

sourceSets {
    main.java.srcDirs += 'src/main/kotlin/'
    test.java.srcDirs += 'src/test/kotlin/'
}

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
    testImplementation 'junit:junit:4.12'
}

jar {
    manifest {
        attributes 'Main-Class': 'com.mallaudin.App'
    }
    from {
        configurations.compile.collect {
            it.isDirectory()? it: zipTree(it)
        }
    }
}

Content of generated jar file

.
├── com
│   └── mallaudin
│       ├── App.class
│       └── User.class
└── META-INF
    ├── basics.kotlin_module
    └── MANIFEST.MF

Content of MANIFEST.MF

Manifest-Version: 1.0
Main-Class: com.mallaudin.App

Exception I get when I run jar form command line

allaudin@geek ~/Desktop/KotlinLab (master) $ java -jar basics/build/libs/basics.jar 
Exception in thread "main" java.lang.NoClassDefFoundError: kotlin/jvm/internal/Intrinsics
    at com.mallaudin.User.<init>(User.kt)
    at com.mallaudin.App.main(App.java:5)
Caused by: java.lang.ClassNotFoundException: kotlin.jvm.internal.Intrinsics
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:583)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:190)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:499)
    ... 2 more
like image 703
mallaudin Avatar asked Dec 15 '18 20:12

mallaudin


People also ask

Can you mix Kotlin and Java in the same project?

Even if it's interop you can't mix Java and Kotlin in the same file. If you really want to have static methods/variables you can use an companion object . You can also access create a "real" static method in your JVM by using @JvmStatic . By using @JvmStatic you can use Java to access your Static methods like before.

Is Kotlin interoperable with Java?

Kotlin is designed with Java interoperability in mind. Existing Java code can be called from Kotlin in a natural way, and Kotlin code can be used from Java rather smoothly as well.

Can you import Kotlin in Java?

Kotlin has been designed from the beginning to fully interoperate with Java, and both JetBrains and Google have pushed in that direction. For instance, IntelliJ and Android Studio allow users to convert files from Java to Kotlin.


1 Answers

The issue is in the way you build your fat jar. While you use the more recent and recommended implementation scope for your dependencies, you are only adding to the fat jar the content of the compile configuration.

You should replace the configuration to be used in the fat jar by runtimeClasspath which is the full set of runtime components.

That is:

jar {
  manifest {
    attributes 'Main-Class': 'com.mallaudin.App'
  }
  from {
    configurations.runtimeClasspath.collect {
      it.isDirectory()? it: zipTree(it)
    }
  }
}  

Have a look at the documentation to understand the different dependency configurations for a java project.

like image 172
Louis Jacomet Avatar answered Oct 05 '22 10:10

Louis Jacomet