24

Usually, we can write the following code in kotlin:

val hasValue : Boolean
    @JvmName("hasValue") get() = true

This will generate the method hasValue() instead of getHasValue() for Java interop.

However, in an interface, this gives me a compile error:

val hasValue : Boolean
   @JvmName("hasValue") get

The same goes for the following declaration in an abstract class:

abstract val hasValue : Boolean
    @JvmName("hasValue") get

So here is my question: How can I tell the kotlin compiler to use hasValue() instead of getHasValue() for getters (and setters) of properties in a kotlin interfaces?

msrd0
  • 7,816
  • 9
  • 47
  • 82

3 Answers3

18

There is a workaround, see: https://youtrack.jetbrains.com/issue/KT-31420

Simply suppress this INAPPLICABLE_JVM_NAME error with annotation: @Suppress("INAPPLICABLE_JVM_NAME")

Nikita Bobko
  • 507
  • 6
  • 13
  • Note that this should be done to **every override** of this member, and see issue comments in YouTrack for details. – Miha_x64 Jun 22 '20 at 19:28
12

I think Kotlin has some restriction on using @JvmName on open/override property/function. Prohibiting the use of @JvmName on open/override function can avoid having different jvmName on the interface/superclass and subclass.

In the following example, I am trying to annotate the overrided property getter with a jvmName (hasValueImpl) which is different from the interface (hasValue) and it gives compilation error:

'@JvmName' annotation is not applicable to this declaration

interface Abstract {

    @get:JvmName("hasValue")        //Compile error
    val hasValue: Boolean
        get() = false
}

open class Impl : Abstract {

    @get:JvmName("hasValueImpl")    //Compile error
    final override val hasValue: Boolean
        get() = false

    @get:JvmName("hasValue2")       //Compile error if hasValue2 is open
    val hasValue2: Boolean
        get() = false
}
Jacky Choi
  • 556
  • 2
  • 6
  • Your argumentation makes sense for override properties, but not for abstract/open properties that override nothing. Although it would mean that if you override an annotated property you'd need to inherit its jvm signature – msrd0 Nov 28 '17 at 07:56
  • 2
    You're right, `@JvmName` is prohibited both for overridden and overridable functions. https://github.com/JetBrains/kotlin/blob/19e38bbc725ec68c9d40bc5c4ad8945266df7231/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/declarationCheckers.kt#L141 @msrd0, this answer is correct and should be accepted. – Miha_x64 Feb 08 '18 at 08:49
  • 1
    @Miha_x64 This answer is correct but yet does not answer the question "how can I tell the Kotlin compiler ...", while it would answer the question "can I tell the Kotlin compiler ..." – msrd0 Feb 08 '18 at 17:53
  • The answer is 'no way'. – Miha_x64 Feb 08 '18 at 20:21
  • Note that Kotlin does not allow the annotation on `inline` classes. – Aanand Kainth Oct 13 '19 at 00:51
5

I turns out, this is possible:

interface Foo {
    val bar: String
        @get:JvmName("getAwesomeBar") get
}

However, it is interesting that this does NOT work:

interface Foo {
    @get:JvmName("getAwesomeBar") 
    val bar: String
}

But, this does work:

class Foo {
    val bar: String
        @JvmName("getAwesomeBar") get() = "My bar value"
}

and this works too!

class Foo {
    @get:JvmName("getAwesomeBar") 
    val bar: String
        get() = "My bar value"
}

Why you need to have the extra get: when doing this in interfaces is beyond me. I'm sure there is a reason for it.

retodaredevil
  • 1,261
  • 1
  • 13
  • 20
  • 1
    There is a reason: using `get() = "My bar value"` is like hardcoding the value for the `val` in your getter body, so you don't need a backing field, whereas just having a `get` requires a backing field to be generated, AFAIK. – Bruno Medeiros Feb 25 '20 at 03:31
  • Note that the first one doesn't seem to actually change the java getter name although the syntax is accepted (JVM/1.6.0-M1). – dan1st Nov 14 '21 at 12:53