Search code examples
kotlintestinggradlektorlocalserver

Receiver class does not define or inherit an implementation of the resolved method 'abstract boolean getDevelopmentMode()'


I'm trying to run local server with KTOR and to cover it with tests. I wrote some code and after writing some tests, the tests successfully raised the local server and passed. However, if I try to start a local server, I get this error

Exception in thread "main" java.lang.AbstractMethodError: Receiver class io.ktor.server.engine.ApplicationEngineEnvironmentReloading does not define or inherit an implementation of the resolved method 'abstract boolean getDevelopmentMode()' of interface io.ktor.application.ApplicationEnvironment.

I attach the code and the stack trace from below

server.kt

import io.ktor.application.*
import io.ktor.features.*
import io.ktor.gson.*
import io.ktor.http.*
import io.ktor.response.*
import io.ktor.routing.*
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable


fun main(args: Array<String>): Unit = io.ktor.server.netty.EngineMain.main(args)

fun Application.module(testing: Boolean = false) {
    install(ContentNegotiation) {
        gson()
    }

    routing {
        val controller = Controller()

        get("/converter{from}{to}") {
            try {
                val fromCurrency = call.request.queryParameters["from"]
                val toCurrency = call.request.queryParameters["to"]
                val rate = controller.converter(fromCurrency, toCurrency)
                val response = Response(
                    "1 $fromCurrency = $rate $toCurrency",
                    null
                )
                call.respond(HttpStatusCode.OK, response)
            } catch (e: ControllerException) {
                val response = Response(
                    null,
                    e.message
                )
                call.respond(HttpStatusCode.BadRequest, response)
            }
        }

        get {
            call.respond(HttpStatusCode.NotFound, Response())
        }
    }
}

@Serializable
data class Response(
    @SerialName("converterResponse")
    val converterResponse: String? = null,
    @SerialName("errorMessage")
    val errorMessage: String? = null
)

converterTest.kt

import com.google.gson.Gson
import io.ktor.application.*
import io.ktor.http.*
import io.ktor.server.testing.*
import kotlin.test.Test
import kotlin.test.assertEquals

class ConverterTest {
    @Test
    fun `Identical Correct Currencies`() {
        withTestApplication(Application::module) {
            handleRequest(HttpMethod.Get, "/converter?from=USD&to=USD").apply {
                assertEquals(HttpStatusCode.OK, response.status())
                val expectedResponse = Response("1 USD = 1 USD")
                assertEquals(
                    Gson().toJson(expectedResponse),
                    response.content
                )
            }
        }
    }
}

stacktrace

Exception in thread "main" java.lang.AbstractMethodError: Receiver class io.ktor.server.engine.ApplicationEngineEnvironmentReloading does not define or inherit an implementation of the resolved method 'abstract boolean getDevelopmentMode()' of interface io.ktor.application.ApplicationEnvironment.
at io.ktor.application.Application.<init>(Application.kt:20)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.instantiateAndConfigureApplication(ApplicationEngineEnvironmentReloading.kt:269)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.createApplication(ApplicationEngineEnvironmentReloading.kt:125)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.start(ApplicationEngineEnvironmentReloading.kt:245)
at io.ktor.server.netty.NettyApplicationEngine.start(NettyApplicationEngine.kt:126)
at io.ktor.server.netty.EngineMain.main(EngineMain.kt:26)
at ServerKt.main(server.kt:11)

build.gradle

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
    kotlin("jvm") version "1.5.30" // or kotlin("multiplatform") or any other kotlin plugin
    application
}

group = "me.admin"
version = "1.0-SNAPSHOT"

repositories {
    jcenter()
    mavenCentral()
    maven { url = uri("https://dl.bintray.com/kotlin/kotlinx") }
    maven { url = uri("https://dl.bintray.com/kotlin/ktor") }
}

dependencies {
    val kotlin_version = "1.5.30"
    val ktor_version = "1.6.3"

    implementation("io.ktor:ktor-server-netty:1.4.0")
    implementation("io.ktor:ktor-client-cio:1.4.0")
    implementation("io.ktor:ktor-html-builder:1.4.0")
    implementation("io.ktor:ktor-client-serialization:1.3.2-1.4-M2")
    implementation("org.jetbrains.kotlinx:kotlinx-html-jvm:0.7.2")
    implementation("org.slf4j:slf4j-api:2.0.0-alpha5")

    implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.0.0-RC")
    implementation(kotlin("stdlib-jdk8"))
    testImplementation("org.jetbrains.kotlin:kotlin-test:$kotlin_version")
    testImplementation("io.ktor:ktor-server-test-host:$ktor_version")
    implementation("io.ktor:ktor-gson:$ktor_version")
}

tasks.test {
    useJUnitPlatform()
}

tasks.withType<KotlinCompile> {
    kotlinOptions.jvmTarget = "1.8"
}

application {
    mainClassName = "ServerKt"
}
val compileKotlin: KotlinCompile by tasks
compileKotlin.kotlinOptions {
    jvmTarget = "1.8"
}
val compileTestKotlin: KotlinCompile by tasks
compileTestKotlin.kotlinOptions {
    jvmTarget = "1.8"
}

Solution

  • The dependency io.ktor:ktor-server-netty:1.4.0 causes the AbstractMethodError. To fix it just use the same version for all Ktor dependencies:

    implementation("io.ktor:ktor-server-netty:$ktor_version")
    implementation("io.ktor:ktor-client-cio:$ktor_version")
    implementation("io.ktor:ktor-html-builder:$ktor_version")
    implementation("io.ktor:ktor-client-serialization:$ktor_version")