0

I have Ktor project that has a main called Application.kt.

The layout is like so

.
└── com
    └── myProject
        ├── Application.kt
        ├── Testing.kt
        ├── api
        │   ├── Routes.kt
        │   └── routes
        │       ├── NewRoutes.kt
        │       ├── OpenApiRoutes.kt
        │       └── OldRoutes.kt
        ├── data
        │   ├── Mongo.kt
        │   ├── model
        │   │   ├── model1
        │   │   │   ├── Model1.kt
        │   │   └── model2
        │   │       ├── Model2.kt
        │   └── repository
        │       ├── MongoRepository.kt
        │       └── Repository.kt

But now I have a script that I would like to run as part of Kubernetes init container, the file looks like this

import com.myProject.data.Mongo
import org.bson.BsonDocument
import org.litote.kmongo.formatJson

class Testing {
  suspend fun test() {
      return whatever
  }

  suspend fun test2() {
     return whatever2
  }
}

suspend fun main() {
  val create = Testing()
  create.test()
  create.test2()
}

i've tried running ./gradlew testing which I have defined in my build.gradle like so:

task testing( type: JavaExec) {
  main = 'com.myProject.Testing'
}

but to no avail, does anybody have any ideas?

When trying to run using the above gradle command i get the error Could not find or load main class Testing

my build.gradle

import org.gradle.api.tasks.testing.logging.TestExceptionFormat

buildscript {
    repositories {
        jcenter()
        maven { url 'https://jitpack.io' }
    }
    
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath 'com.github.jengelman.gradle.plugins:shadow:6.1.0'
    }
}


task testing( type: JavaExec) {
  main = 'com.myProject.Testing'
  classpath = sourceSets.main.runtimeClasspath
}


tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
    kotlinOptions {
        jvmTarget = "1.8"
    }
}

apply plugin: "java"
apply plugin: 'kotlin'
apply plugin: 'application'
apply plugin: 'com.github.johnrengelman.shadow'
apply plugin: 'jacoco'

group 'com.myProject'
version '0.0.1'
mainClassName = "io.ktor.server.netty.EngineMain"

shadowJar {
    manifest {
        attributes 'Main-Class': mainClassName
    }
}

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

repositories {
    mavenCentral()    
    jcenter()
    maven { url 'https://jitpack.io' }
    maven { url 'https://kotlin.bintray.com/ktor' }
}
4
  • In any case, I don't believe main() can be suspend. You should maybe remove the modifier and wrap the body into runBlocking { ... } to make it "main-compliant" Commented Mar 16, 2021 at 10:34
  • Also what's the name of the file you declared this code in? Because the fully qualified class name for the top-level main should be the package name + . + file name + Kt suffix (unless you use @file:JvmName to customize the name of the generated class that wraps top-level declarations) Commented Mar 16, 2021 at 10:36
  • Does this answer your question? proper way to run kotlin application from gradle task. If not, please post your exact error so we can help you more easily. Commented Mar 16, 2021 at 10:43
  • I updated my question with more information such as project structure and my build.gradle Commented Mar 16, 2021 at 11:22

2 Answers 2

2

Your main function is not part of the Testing class. So com.myProject.Testing is not a valid main class name.

You should either move your main method to the companion object of the Testing class (like a static method of the class), or change the gradle build file to use the generated class name for top-level declarations, which follows the convention:

package_name + . + capitalized_file_name + Kt

If your file is named Testing.kt, and the package of your declarations is com.myProject, your fully qualified main class name should be:

com.myProject.TestingKt (note the Kt at the end)

But I don't see a package declaration at the top of Testing.kt. Did you just omit it for brevity or did you actually forget it?

Sign up to request clarification or add additional context in comments.

Comments

2

You can use the following format to define a task:

task <task-name>(type: JavaExec) {
    main = '[<package>.]<file-class>'
    classpath = sourceSets.main.runtimeClasspath
}

where <task-name> — the name for a Gradle task, <package> — package where your script class resides, <file-class> — uppercased filename without extension + Kt suffix.

For example, if I call a task runScript and the script is located in /src/main/kotlin/script.kt (top level package) then the task definition will be the following:

task runScript(type: JavaExec) {
    main = 'ScriptKt'
    classpath = sourceSets.main.runtimeClasspath
}

2 Comments

That gives me a Could not get unknown property 'sourceSets' for task error when I run that. I've updated my question with project structure and my build.gradle if that helps at all.
@Strobe_ just move your task definition after the apply plugins block.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.