Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to configure build.gradle.kts to fix error "Duplicate JVM class name generated from: package-fragment"

I'm trying to follow this tutorial https://dev.to/tagmg/step-by-step-guide-to-building-web-api-with-kotlin-and-dropwizard and am instead writing my gradle.build file in Kotlin's DSL and am finding there is no direct mapping from Groovy to Kotlin and I'm now getting this error when running ./gradlew run:

(4, 1): Duplicate JVM class name 'dropwizard/tut/AppKt' generated from: package-fragment dropwizard.tut, package-fragment dropwizard.tut
plugins {
    // Apply the Kotlin JVM plugin to add support for Kotlin on the JVM.
    id("org.jetbrains.kotlin.jvm").version("1.3.31")

    // Apply the application plugin to add support for building a CLI application.
    application
}

repositories {
    // Use jcenter for resolving dependencies.
    // You can declare any Maven/Ivy/file repository here.
    mavenCentral()
    jcenter()
}

dependencies {
    // Use the Kotlin JDK 8 standard library.
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")

    // Use the Kotlin test library.
    testImplementation("org.jetbrains.kotlin:kotlin-test")

    // Use the Kotlin JUnit integration.
    testImplementation("org.jetbrains.kotlin:kotlin-test-junit")

    compile("io.dropwizard:dropwizard-core:1.3.14")
}

application {
    // Define the main class for the application
    mainClassName = "dropwizard.tut.AppKt"
}

tasks.withType<Jar> {
    manifest {
        attributes["Main-Class"] = application.mainClassName 
    }
    from({
        configurations.runtimeClasspath.get().filter { it.name.endsWith("jar") }.map { zipTree(it) }
    })
}

tasks.named<JavaExec>("run") {
    args("server", "config/local.yaml")
}
like image 710
Quilty Kim Avatar asked Sep 02 '19 21:09

Quilty Kim


2 Answers

I cannot tell (yet) why this happens but to work around it add @file:JvmName("SomethingUnique") to your JVM file. Note that renaming the file will not help and lead to the same error. Only changing the output name will resolve it.

like image 190
Fleshgrinder Avatar answered Oct 14 '22 17:10

Fleshgrinder


The JVM only knows how to load classes, so the Kotlin-to-JVM compiler generates classes to hold top-level val or fun declarations.

When you have two similarly named files

// src/commonMain/kotlin/com/example/Foo.kt
package com.example

val a = 1

and

// src/jvmMain/kotlin/com/example/Foo.kt
package com.example

val b = 2

the kotlin-to-JVM compiler generates

package com.example;
public class FooKt {
  public static final int a = 1;
}

and

public com.example;
public class FooKt {
  public static final int b = 2;
}

Obviously, these two files can't coexist in the same JVM ClassLoader, hence the error message.

Solutions involve:

  • As @Fleshgrinder noted, adding a file-level JvmName annotation to at least one to override the derived name, FooKt.
  • Renaming files to be different where possible.
  • Moving top-level val and fun declarations from those files into other files so Kotlin does not need to create the FooKt class.
  • Moving top-level val and fun declarations into objects or companion objects.
like image 23
Mike Samuel Avatar answered Oct 14 '22 15:10

Mike Samuel