Kotlin: classpath trouble

I’m trying to get a Kotlin Ktor project running. I can build a jar with my gradle script but trying to run the jar errors out with a ClassNotFoundException for the class that contains my main method. Indeed, when looking at the MANIFEST.MF file there is no classpath defined so no wonder the entry point isn’t found.

However, I can’t figure out how to fix this. I’ve cobbled together my gradle script from various examples on the internet but none of them seem to set the classpath explicitly to anything.

Googling led me to try to set the classpath manually with the following:

jar {
    manifest {
        attributes(
            'Main-Class': application.mainClass, // defined earlier
            'Class-Path': configurations.compile.collect { it.getName() }.join(' '))
    }
}

but compile is deprecated and I’m not sure what to substitute it with.

Here’s a Build Scan for good measure although the build itself works perfectly fine: Build Scan™ | Gradle Cloud Services

And here’s my build.gradle since I don’t think its contents are included in the Build Scan:

plugins {
	id 'application'
	id 'org.jetbrains.kotlin.jvm' version '1.7.10'
	id 'org.jetbrains.kotlin.plugin.serialization' version '1.7.10'
}

group = 'la.sakuer'
version = '0.0.1'

final String devmode = hasProperty('devmode') && getProperty('devmode') == 'true' ? 'true' : 'false'
final String ktor_version = '2.0.3'

application {
	mainClass = 'la.sakuer.bilebandi.ApplicationKt'
	applicationDefaultJvmArgs = [ "-Dio.ktor.development=$devmode" ]
}

repositories {
	mavenCentral()
}

sourceSets {
	main.kotlin.srcDirs = [ 'src/main' ]
	main.resources.srcDirs = [ 'src/main/resources' ]
	test.kotlin.srcDirs = [ 'src/test' ]
}

kotlin {
	sourceSets {
		main {
			dependencies {
				implementation "io.ktor:ktor-server-core-jvm:$ktor_version"
				implementation "io.ktor:ktor-server-tomcat-jvm:$ktor_version"
				implementation "io.ktor:ktor-server-html-builder:$ktor_version"
				implementation "io.ktor:ktor-server-content-negotiation:$ktor_version"
				implementation "io.ktor:ktor-serialization-kotlinx-json:$ktor_version"

				implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.0-RC'
				implementation 'com.google.cloud:google-cloud-firestore:3.3.0'

				implementation 'ch.qos.logback:logback-classic:1.2.11'
			}
		}

		test {
			dependencies {
				implementation "io.ktor:ktor-server-tests-jvm:$ktor_version"
				implementation 'org.jetbrains.kotlin:kotlin-test-junit'
			}
		}
	}
}

compileKotlin {
    kotlinOptions.jvmTarget = '17'
}

tasks.register('postBuild') {
	doFirst {
		println 'Built with development mode: ' + devmode
	}
}

tasks.named('build') { finalizedBy('postBuild') }

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

	// works around a bug, perhaps not optimal but no one seems to have a fix
	duplicatesStrategy = DuplicatesStrategy.INCLUDE
}

The entry point is at src/main/Application.kt, in package la.sakuer.bilebandi. Gradle version is 7.5.

So, what would be the proper way to include the entry point in the classpath?

As you already use the application plugin, I’d suggest you remove those jar manifest entries and actually use the application plugin to build a proper application instead of a fat jar.
Here you have its documentation: The Application Plugin
You use distTar or distZip to create a proper distributable archive with all your code, your dependencies and start scripts to properly run your application.

Thanks! That pushed me to the right direction. A simple JAR would have been fine too, but installDist in a Dockerfile and a corresponding ENTRYPOINT work for me. :+1: