36

I'm trying to introduce Kotlin into my current project. I've decided to begin with entities, which seem to map perfectly to data classes. For example I have a data class:

data class Video(val id: Long, val ownerId: Long, val title: String, val description: String? = null,
             val imgLink: String? = null, val created: Date? = null, val accessKey: String? = null,
             val views: Long? = null, val comments: Long? = null, val videoLink: String? = null): Entity

Which implements Java interface:

public interface Entity {
   Long getId();  
}

But for some reason compiler doesn't understand that method is implemented already:

Class 'Video' must be declared abstract or implement abstract member public abstract fun getId(): kotlin.Long! defined in net.alfad.data.Entity

Do I have to use any additional keywords for id param? What does "!" mean in the signature?

hotkey
  • 140,743
  • 39
  • 371
  • 326
Odysseus
  • 1,032
  • 2
  • 12
  • 14
  • 1
    `!` in the signature means that this is a platofrm type, i.e. a type coming from Java. You can find out more about that [in the docs](http://kotlinlang.org/docs/reference/java-interop.html#notation-for-platform-types) – Alexander Udalov Feb 25 '16 at 17:18

2 Answers2

54

The problem here is that Kotlin loads the Java class Entity first and it sees getId as a function, not as a getter of some property. A property getter in a Kotlin class cannot override a function, so the property id is not bound as an implementation of the getId function.

To workaround this, you should override the original function getId in your Kotlin class. Doing so will result in JVM signature clash between your new function and id's getter in the bytecode, so you should also prevent the compiler from generating the getter by making the property private:

data class Video(
    private val id: Long,
    ...
): Entity {
    override fun getId() = id

    ...
}

Note that this answer has been adapted from here: https://stackoverflow.com/a/32971284/288456

Phileo99
  • 5,581
  • 2
  • 46
  • 54
Alexander Udalov
  • 31,429
  • 6
  • 80
  • 66
  • Nice answer! One more thing: does this mean that getters/setters are not regular methods as in Java? – Odysseus Feb 25 '16 at 16:09
  • 2
    In the resulting bytecode, and from Java's point of view, they are the same. A property getter is compiled to a method named `getXxx`. But for Kotlin (version 1.0.0), property accessors and functions are different and you can't mix the two in the hierarchy. – Alexander Udalov Feb 25 '16 at 17:16
  • Is there any discussion about changing this? Is there a reason this shouldn't just _work_? – Christian Bongiorno Jun 02 '17 at 23:54
  • 1
    There's [an issue here](https://youtrack.jetbrains.com/issue/KT-6653). One of the problems is that you can't override a `val x` by a `fun getX` or vice versa in Kotlin (by design), so all kinds of complex questions show up if you have a mixed hierarchy of Kotlin and Java code where some classes use properties and some -- functions. – Alexander Udalov Jun 05 '17 at 08:28
  • Base on this answer, I thought moving the interface to Kotlin as well would solve the issue, but it doesn't, is that because the bytecode is still created as if it was a java class because I'm still in a mixed project? – avalancha Mar 12 '23 at 07:19
  • @avalancha Converting the interface to Kotlin and changing get-methods to properties (`fun getX` -> `val x`) would solve it. – Alexander Udalov Mar 13 '23 at 14:48
1

If this is your whole data class then you're not overriding getId(). I see that you have a property called id and Kotlin should generate a getter for that but that won't be marked with the override keyword which you need to indicate that you're overriding an abstract function.

-- EDIT -- Alexander beat me to it! His answer is better anyway! ;)

CaseyB
  • 24,780
  • 14
  • 77
  • 112