Kotlin class does not implement interface methods but abstract class does implement methods - kotlin

I'm using spring boot version 2.1.9 with spring-data. I've defined a repository
interface TokenRepository : CrudRepository<Token, Long> {
fun findBySubject(subject: String): Token?
}
For testing purposes I've created an abstract fake of a CrudRepository which implements all methods from the CrudRepository:
abstract class RepositoryFake<T> : CrudRepository<T, Long> {
...
override fun existsById(id: Long): Boolean {
...
}
override fun deleteById(id: Long) {
...
}
override fun findById(id: Long): Optional<T> {
...
}
...
}
Now when I create an implementation of the TokenRepository which extends the RepositoryFake
class TokenRepositoryFake : RepositoryFake<Token>(), TokenRepository {
override fun findBySubject(subject: String): Token? {
...
}
}
the compiler complains that the TokenRepositoryFake is not abstract and it does not implement the methods existsById, deleteById and findById despite those methods being implemented in RepositoryFake. It does not complain about the other methods defined in CrudRepository. Why is the compiler complaining about missing methods and not about all the other methods?
An example of the error message:
Class 'TokenRepositoryFake' is not abstract and does not implement abstract member public abstract fun deleteById(p0: Long): Unit defined in my.repositories.TokenRepository

I think I found the issue. If I change the type of the RepositoryFake to
abstract class RepositoryFake<T, ID> : CrudRepository<T, ID>
and then change the TokenRepositoryFake to
class HDChainRepositoryFake : RepositoryFake<HDChain, Long>(), HDChainRepository
everything compiles. I'm assuming it has something to do with the way that kotlin handles generics, but don't exactly know why.

Related

Custom Gradle Task having Kotlin Delegate

Gradle tasks using Kotlin are implemented as either abstract class ... or interface ....
In either case it is not clear how to use delegation.
The following works correctly but requires delegation to be performed manually (i.e. it does not use Kotlin delegation).
#CacheableTask
abstract class FooTask : DefaultTask(), CopySourceSpec {
#get:InputFiles
#get:Optional
#get:SkipWhenEmpty
#get:IgnoreEmptyDirectories
#get:PathSensitive(PathSensitivity.RELATIVE)
abstract val sourceFiles: ConfigurableFileCollection
#TaskAction
fun canonize() {
val sourceFileTree = sourceFiles.asFileTree
// do something with the sourceFileTree
}
override fun from(vararg sourcePaths: Any?): ProtobufHeaderTask {
this.sourceFiles.from(sourcePaths)
return this
}
override fun from(sourcePath: Any, closure: Closure<*>): ProtobufHeaderTask {
this.sourceFiles.from(sourcePath, closure)
return this
}
override fun from(sourcePath: Any, configureAction: Action<in CopySpec>): ProtobufHeaderTask {
this.sourceFiles.from(sourcePath, configureAction)
return this
}
}
It seems like this could be done more simply using Kotlin delegation.
#CacheableTask
abstract class FooTask : DefaultTask(), ConfigurableFileCollection by sourceFiles {
#get:InputFiles
#get:Optional
#get:SkipWhenEmpty
#get:IgnoreEmptyDirectories
#get:PathSensitive(PathSensitivity.RELATIVE)
abstract val sourceFiles: ConfigurableFileCollection
#TaskAction
fun canonize() {
val sourceFileTree = sourceFiles.asFileTree
// do something with the sourceFileTree
}
}
This latter case produces an error that sourceFiles is not defined.
Is it possible to use Kotlin delegation in this way?

Serializer for sealed interface (kotlinx.serialization)

I am trying to serialize my base class that is implementing two sealed interfaces. I have tried multiple approaches, yet i always get the error :
caused by: kotlinx.serialization.SerializationException: Class 'PayloadFromBuilder' is not registered for polymorphic serialization in the scope of 'Payload'.
Mark the base class as 'sealed' or register the serializer explicitly.
I was following mostly this guide Kotlinx/polymorphism and checked some similar questions here.
My code:
sealed inteface MyClass {
dataetc
}
#Serializable
private class DefaultMyClass(dataetc): MyClass
fun MyClass(dataetc): MyClass = DefaultMyClass
Sealed interface MyClassBuilder {
fun dataetc(value: ByteArray)
fun dataetc(value: ByteArray)
fun dataetc(value: ByteArray?)
}
#PublishedApi
#Serializable
#SerialName("payload")
internal class MyClassFromBuilder: MyClassBuilder, MyClass {
}
//Serialization
val module = SerializersModule {
polymorphic(MyClass::class) {
subclass(MyClassFromBuilder::class, MyClassFromBuilder.serializer())
default { MyClassFromBuilder.serializer() }
}
polymorphic(MyClassBuilder::class) {
subclass(MyClassFromBuilder::class, MyClassFromBuilder.serializer())
default { MyClassFromBuilder.serializer() }
}
}
val ConfiguredProtoBuf = ProtoBuf { serializersModule = module }
#ExperimentalSerializationApi
internal inline fun <reified T> ProtoBuf.encodeToMessage(value: T): Message =
Message(encodeToByteArray(value))
From what i have seen i think i am very close to the solution yet i am missing something, since my example is very generic if you need more info let me know, thank you in advance.
Note: In my several tries i have tried to annotate both sealed intefaces with #Polymorphic but i am not sure if it changed anything.
Note 2: My code breaks when i am calling the encodeToMessage fun
So i messed big time, turns out i was not using my ConfiguredProtoBuf when i was calling my encodeToMessage

How to create a class with a method that returns a subtype with a type parameter in Kotlin?

I am struggling to understand how generics / type parameters work in Kotlin. I am working on a (fairly complex) app that is throwing some very confusing error messages during compilation. I've simplified things below to the minimum amount of code that will reproduce the error.
I have an interface and two abstract classes:
interface Player {
fun play()
}
abstract class Device <T : Player> {
abstract fun getPlayer(): T
}
abstract class DeviceFactory {
abstract fun <T : Player> create(): Device<T>
}
The problem arises when I try to create a class that implements DeviceFactory:
class MyDeviceFactory : DeviceFactory() {
class MyPlayer : Player {
override fun play() {
println("[sound plays here]")
}
}
class MyDevice : Device<MyPlayer>() {
override fun getPlayer() = MyPlayer()
}
override fun create() = MyDevice()
}
The last line of code is where the problem arises, yielding the following error message:
Conflicting overloads: public open fun create(): MyDeviceFactory.MyDevice defined in MyDeviceFactory,
public abstract fun create(): Device defined in DeviceFactory
Thinking that maybe the problem was the missing type parameter, I tried this instead:
override fun <T : Player> create() = MyDevice()
Now I have a different error message:
Return type of 'create' is not a subtype of the return type of the overridden member
'public abstract fun create(): Device defined in DeviceFactory'
This doesn't make sense — MyDevice is a subtype of Device<T>, right? To be sure, I tried making the return type explicit:
override fun <T : Player> create(): Device<T> = MyDevice()
No dice:
Type mismatch: inferred type is MyDeviceFactory.MyDevice but Device was expected
How can I create a class that derives from DeviceFactory and returns an instance of MyDevice?
You need to declare the type for DeviceFactory on it's class:
abstract class DeviceFactory<T : Player> {
abstract fun create(): Device<T>
}
Then you can define a factory that returns a concrete Player:
class MyDeviceFactory : DeviceFactory<MyPlayer>() {
override fun create(): Device<MyPlayer> = MyDevice()
}

Parcelable overload resolution ambiguity

I am trying to create a POJO (aka data classes in Kotlin) structure of a JSON response in Kotlin. I've implemented the Parcelable interface for each data class in the structure. In all of the data classes, I've auto generated the Parcelable implementation. The issue is the generated second constructor where the IDE is complaining about:
Overload resolution ambiguity
It states that it's being confused between these two constructors:
public constructor GeocodeRes(parcel: Parcel)
public constructor GeocodeRes(responset: ResponseRes)
Which I believe makes sense because ResponseRes is also of type Parcelable (ResponseRes implements Parcelable). So calling the GeocodeRes(parcel) method (within the createFromParcel companion method), it is getting confused.
That was until I removed ResponseRes from implementing the Parcelable class and it's still showing the same error.
Is there any reason to this? Am I setting this up properly? In all of the children data classes, they all implement the Parcelable interface (with dependence with eachother) but aren't running into any issues.
Here's my GeocodeRes class:
import android.os.Parcel
import android.os.Parcelable
import com.google.gson.annotations.Expose
import com.google.gson.annotations.SerializedName
data class GeocodeRes(
#SerializedName("Response") #Expose val responset: ResponseRes
) : Parcelable {
// this is the problem. the IDE is complaining that the usage is too ambiguous (). however, the only usage of this constructor is within this class - just doesn't tell me where exactly.
constructor(parcel: Parcel) : this(parcel.readParcelable(ResponseRes::class.java.classLoader)) {
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeParcelable(responset, flags)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<GeocodeRes> {
override fun createFromParcel(parcel: Parcel): GeocodeRes {
return GeocodeRes(parcel)
}
override fun newArray(size: Int): Array<GeocodeRes?> {
return arrayOfNulls(size)
}
}
}
Here's my ResponseRes class:
data class ResponseRes(
#SerializedName("MetaInfo") #Expose val metaInfo: MetaInfo,
#SerializedName("View") #Expose val views: List<View>
): Parcelable
{
[...]//parcel methods
}
however, the only usage of this constructor is within this class - just doesn't tell me where exactly
The problem is with the definition itself, not with any usage. It could never be used, and the error would still be there.
You should be able to fix this by specifying which Parcelable you want to read:
this(parcel.readParcelable<ResponseRes>(ResponseRes::class.java.classLoader))
The compiler can't decide if you mean that or
this(parcel.readParcelable<Parcel>(ResponseRes::class.java.classLoader))
Even though the second wouldn't be legal because Parcel doesn't implement Parcelable, if you look at the signature
<T extends Parcelable> T readParcelable(ClassLoader loader)
you can see only the return type can be used to infer T, not the argument. So the compiler need to pick the constructor overload before trying to infer T.

Static Instance of Interface as part of the interface

Imagine I had an interface like:
interface MyInterface {
fun doSomething()
}
And I was interop-ing between Kotlin and Java. I now want a constant static instance of this interface but I want that to be part of the interface. I could do this:
interface MyInterface {
fun doSomething()
companion object {
val CONSTANT = object: MyInterface {
override fun doSomething() { ... }
}
}
}
but that means I need to write MyInterface.Companion.getCONSTANT(). #JvmField doesn't work here.
I've also tried:
interface MyInterface {
fun doSomething()
object CONSTANT: MyInterface {
override fun doSomething() { ... }
}
}
}
Which works in other Kotlin files (I can write MyInterface.CONSTANT) but I'd have to write MyInterface.CONSTANT.INSTANCE in Java. This solution seems the closest to what I want.
Any solutions? I want to be able to write MyInterface.CONSTANT in both Kotlin and Java and have them refer to a single static final object that implements the interface.
I believe I could also convert my Interface to an abstract class but that's the last resort.
The issue of not being able to use #JvmStatic in interfaces is tracked in this ticket: https://youtrack.jetbrains.com/oauth?state=%2Fissue%2FKT-6301
It is fixed by now and one comment says
Fix would be avaliable in 1.2.30 under '-language-version 1.3' option