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
?
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
?
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"
}
}
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.
@Target([AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY])
annotation classJvmDefault
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 theDefaultImpls
class.with
-Xjvm-default=compatibility
, in addition to the default interface method, a compatibility accessor is generated in theDefaultImpls
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
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.
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 addIDEA
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.