49

I need to make a default void method in a Kotlin interface. I ran into a problem and a hint said Usage of @JvmDefault is only allowed with -Xjvm-default option.

Where do I need to write this Xjvm-default?

Markus Weninger
  • 11,931
  • 7
  • 64
  • 137
Evgesha
  • 491
  • 1
  • 4
  • 4
  • 2
    Question is unclear. Please see [How do I ask a good question](https://stackoverflow.com/help/how-to-ask) – coderpc Dec 28 '18 at 21:00

5 Answers5

51

@Target([AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY]) annotation class JvmDefault

Specifies that a JVM default method should be generated for non-abstract Kotlin interface member.

Usages of this annotation require an explicit compilation argument to be specified: either -Xjvm-default=enable or -Xjvm-default=compatibility.

with -Xjvm-default=enable, only default method in interface is generated for each @JvmDefault method. In this mode, annotating an existing method with @JvmDefault can break binary compatibility, because it will effectively remove the method from the DefaultImpls class.

with -Xjvm-default=compatibility, in addition to the default interface method, a compatibility accessor is generated in the DefaultImpls class, that calls the default interface method via a synthetic accessor. In this mode, annotating an existing method with @JvmDefault is binary compatible, but results in more methods in bytecode.

Removing this annotation from an interface member is a binary incompatible change in both modes.

Generation of default methods is only possible with JVM target bytecode version 1.8 (-jvm-target 1.8) or higher.

@JvmDefault methods are excluded from interface delegation.

https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/-jvm-default/index.html

if you use gradle then add this parameter to gradle script

https://kotlinlang.org/docs/reference/using-gradle.html

for example add this to gradle:

kotlinOptions {
    freeCompilerArgs = ['-Xjvm-default=compatibility']
}

otherwise if you use Kotlinc command line compiler add -Xjvm-default=compatibility after your command in command line

ygngy
  • 3,630
  • 2
  • 18
  • 29
  • 4
    Copying the documentation text without additional information is most probably not very helpful on how to pass flags to the compiler. – Markus Weninger Dec 29 '18 at 01:25
  • Thank you, but I never received an answer ... How to add to the arguments? – Evgesha Dec 29 '18 at 09:19
  • @Evgesha if you use gradle build system add it to gradle build script https://kotlinlang.org/docs/reference/using-gradle.html – ygngy Dec 29 '18 at 10:29
  • @Evgesha i added answer to your question in my answer – ygngy Dec 29 '18 at 10:33
  • I'm trying to apply this answer, but I'm not sure where to put it in my `build.gradle.kts` file. If I put it directly in `tasks`, `kotlinOptions` isn't recognized. If I put it in `tasks` > `compileKotlin`, I get "Unsupported [Collection literals outside of annotation]" as an error on `["-Xjvm-default=compatibility"]`. – kshetline May 09 '20 at 22:08
  • 1
    @kshetline if you open `build.gradle` inside `app` folder there is a `android { }` put it between `{` and `}` of `android` – ygngy May 10 '20 at 16:25
  • @Bahman, I'm not doing Android development here, but I did eventually put `kotlinOptions.freeCompilerArgs = listOf("-Xjvm-default=enable")` inside both `compileKotlin{ }` and `compileTestKotlin{ }`, and that did the trick. Turns out that `listOf()` syntax was necessary to make Kotlin happy inside a `build.gradle.kts` file. – kshetline May 10 '20 at 18:00
  • Perfect answer. @Evgesha this should be marked as accepted answer. – mohitum Jul 20 '22 at 13:09
24

The new answer since Kotlin 1.4 would be:

tasks.withType(KotlinCompile::class).all {
    kotlinOptions {
        jvmTarget = "11"

        // For creation of default methods in interfaces
        freeCompilerArgs = listOf("-Xjvm-default=all")
    }
}

You can then even leave off the @JvmDefault completely!

Cf. https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#default-methods-in-interfaces.

Michael Piefel
  • 18,660
  • 9
  • 81
  • 112
14

In root build.gradle add below code

allprojects {
    //Support @JvmDefault
    tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
        kotlinOptions {
            freeCompilerArgs = ['-Xjvm-default=enable'] //enable or compatibility
            jvmTarget = "1.8"
    }
}
Fang
  • 3,652
  • 4
  • 16
  • 30
1

This question regarding @JvmDefault seems rather similar to this one.

The -Xjvm-default=enable flag has to be passed to the compiler. Since I assume that you do not work with kotlinc (the Kotlin compiler) directly on the command-line: This Q&A contains information on how to pass flags to the Kotlin compiler when using Gradle.

Markus Weninger
  • 11,931
  • 7
  • 64
  • 137
1

Additional relevant failure output can be: is not abstract and does not override abstract method.

About passing the -Xjvm-default flag:

maven

in the plugin configuration node for kotlin-maven-plugin add

<args>
  <arg>-Xjvm-default=all</arg>
</args>

IDEA

in Preferences (via dev.to): Build, Execution, Deployment -> Compiler -> Kotlin Compiler -> Additional command line parameters add -Xjvm-default=all

in Project Structure: Modules -> Kotlin -> Additional command line parameters add -Xjvm-default=all

@JvmDefault should not be necessary with kotlin > 1.4 but there may be special constellations in which the manual should help determine which combination of annotation and flag is required.

dave
  • 1,314
  • 1
  • 11
  • 18