多模块Kotlin-Gradle项目打可执行Jar后Kotlin Object初始化失败
java.lang.NoClassDefFoundError for Kotlin Object in Fat Jar Let's break down why you're hitting this error and how to fix it—even though the class exists in your jar, the JVM can't initialize it properly, which is what this error is really signaling (it's not that the class is missing, but that its initialization failed).
1. First: Uncover Hidden Initialization Exceptions
Kotlin objects are initialized lazily when first accessed, and if their init block (or property initializers) throw an exception, the JVM marks the class as failed to initialize—and subsequent attempts to access it throw NoClassDefFoundError without showing the original exception.
Add explicit error handling to your object to expose any hidden issues:
object MyKotlinObjectClass { init { try { // Wrap all your existing initialization logic here println("Initializing MyKotlinObjectClass...") // Example: If you're loading config files or external resources, add logs here } catch (e: Throwable) { e.printStackTrace(System.err) throw e // Re-throw to preserve the original error } } // Your existing variables }
Re-package your jar and run java -jar again—you should now see the root cause exception in the output.
2. Fix Your Gradle Fat Jar Configuration
For Custom Jar Tasks
Your current setup uses compileClasspath, which in newer Gradle versions (7+) doesn't include all runtime dependencies (like Kotlin stdlib, or transitive dependencies from other modules). Switch to runtimeClasspath instead, and add a duplicates strategy to handle overlapping classes:
jar { manifest { attributes( 'Main-Class': 'my_package.RunnerKt' ) } // Use runtimeClasspath to include all runtime dependencies from { configurations.runtimeClasspath.filter{ it.exists() }.collect { it.isDirectory() ? it : zipTree(it) } } // Handle duplicate classes (adjust based on your needs: INCLUDE, EXCLUDE, or FAIL) duplicatesStrategy = DuplicatesStrategy.INCLUDE }
For Shadow Plugin
Make sure you're configuring Shadow to use the correct classpath and explicitly set the main class. Also, ensure your Shadow and Kotlin plugin versions are compatible (e.g., Shadow 7.x works with Gradle 7+ and Kotlin 1.7+):
plugins { id 'org.jetbrains.kotlin.jvm' version '1.9.20' id 'com.github.johnrengelman.shadow' version '7.1.2' } shadowJar { manifest { attributes 'Main-Class': 'my_package.RunnerKt' } // Explicitly use runtimeClasspath to include all required dependencies configurations = [project.configurations.runtimeClasspath] } // Optional: Tie shadowJar to the assemble task so it runs automatically assemble.dependsOn(shadowJar)
3. Verify Multi-Module Dependencies
Double-check that the module containing MyKotlinObjectClass is correctly added as a dependency to your main module:
// In your main module's build.gradle dependencies { implementation project(':module-with-your-object') // Other dependencies... }
You can also verify the class is actually in the jar by running:
jar tf your-fat-jar.jar | grep MyKotlinObjectClass
You should see entries like my/kotlin/object/class/MyKotlinObjectClass.class.
4. Check for Circular Initialization or Classpath Conflicts
- Circular Dependencies: If your Kotlin object references another class that also references the object, you'll get a silent initialization failure. Audit your code for circular dependencies between objects/classes.
- Duplicate Classes: If your fat jar contains multiple versions of the same class (from conflicting dependencies), the JVM might load the wrong one. For Shadow, use the
relocatefeature to package conflicting dependencies under a unique namespace, or setduplicatesStrategy = DuplicatesStrategy.FAILduring packaging to catch duplicates early.
内容的提问来源于stack exchange,提问作者Andranik

