I'm trying to implement an abstract class in kotlin which extends a MultiValuedMap, when I was trying to override keySet() method, I got the error
platform declaration clash: The following declarations have the same JVM signature (keySet()Ljava/util/Set;)
My code:
abstract class ConfigProperties<K, V>(delegate: Map<K, V>?): MultivaluedMap<String, String> {
protected val delegate: Map<K, V>
init {
if (delegate == null) {
throw NullPointerException("Config properties delegate must not be null.")
}
this.delegate = delegate
}
abstract fun putCacheProperty(key: Parameter, value: Any)
abstract fun getCacheProperty(key: Parameter): Any
protected val UNSUPPORTED_MESSAGE = "ConfigProperties is immutable."
override fun keySet(): Set<String> {
return delegate.keys
}
}
Any hint to solve this? Thanks!
I think your problem begins with MultivaluedMap<String,String>
abstract class ConfigProperties<K, V>(delegate: Map<K, V>?):
MultivaluedMap<String, String> { ... }
Overlook the String type parameter for the moment. MultivaluedMap<K,V> is an interface that has the Map<K,List<V>> super interface. But in your code, you have a delegate of type Map<K,V>. You try to override a the setKey member of the Map<K,List<V>> super interface by returning delegate.keys which is not the same as Map<K,List<V>>.keys (i.e., whose member you are overriding).
So, you can try the following...
abstract class ConfigProperties<K, V>(delegate: Map<K, V>?):
MultivaluedMap<K, V> {
protected val delegate: Map<K, List<V>>
init {
if (delegate == null) {
throw NullPointerException("Config properties delegate must not be null.")
}
this.delegate = delegate
}
abstract fun putCacheProperty(key: Parameter, value: Any)
abstract fun getCacheProperty(key: Parameter): Any
protected val UNSUPPORTED_MESSAGE = "ConfigProperties is immutable."
override fun keySet(): Set<K> {
return delegate.keys
}
}
As for the String type parameter, did you mean to use K,V? Whatever you meant, you will need to make the consistent.
Related
Is it impossible to use generic on interface level as argument type for function?
I read about out and in keywords but as I understand they don't work for this case.
interface BaseB
open class ChildB1: BaseB
open class ChildB2: BaseB
abstract class BaseMapper<V: BaseB> {
open fun test(v: V) {
return
}
}
class TestMapper1: BaseMapper<ChildB1>() {
override fun test(v: ChildB1) {
return
}
}
class TestMapper2: BaseMapper<ChildB2>() {
override fun test(v: ChildB2) {
return
}
}
#Test
fun t() {
//ERROR
val mappers: List<BaseMapper<BaseB>> = listOf(TestMapper1(), TestMapper2())
mappers[0].test(ChildB1())
}
A BaseMapper<ChildB1> is not logically a BaseMapper<BaseB>. It consumes ChildB’s, so if you passed some other implementation of Base it would cause a ClassCastException if the compiler let you do that. There is no common subtype of your two subclasses besides Nothing, so the only way to put both of these types in the same list is to make it a List<BaseMapper<in Nothing>>.
Example of why it is not logically a BaseMapper<BaseB>:
open class ChildB1: BaseB {
fun sayHello() = println("Hello world")
}
class TestMapper1: BaseMapper<ChildB1>() {
override fun test(v: ChildB1) {
v.sayHello() // if v is not a ChildB1, this would be impossible
}
}
//...
val impossibleCast: BaseMapper<BaseB> = TestMapper1()
// TestMapper1 cannot call sayHello() because it's undefined for ChildB2.
// This is impossible:
impossibleCast.test(ChildB2())
// ...so the compiler prevents you from doing the impossible cast in the first place.
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()
}
I have the following code -
package multipleInterfaceDemo
fun main() {
println(MyClass(val1 = 1, val2 = 2).myFun())
}
private class MyClass(override val val1: Int, override val val2: Int): MyInterface1, MyInterface2 {
/*override fun myFun() {
super<MyInterface1>.myFun()
}*/
override fun myFun() {
super<MyInterface2>.myFun()
}
}
private interface MyInterface1 {
val val1: Int
public fun myFun() {
println(val1)
}
}
private interface MyInterface2 {
val val2: Int
public fun myFun() {
println(val2)
}
}
Here I have two private Interfaces - MyInterface1 and MyInterface2
Each interface has an Int type variable - val1 and val2 respectively which are set through constructors in implementing Class
Both my Interfaces have a method called myFun() which prints out val1 and val2 respectively.
Now I have a class MyClass that implements MyInterface1 and MyInterface2.
The Class has two constructor parameters for setting the variable values in the two interfaces implemented by the Class
Now both the Interfaces have a method having similar name - myFun() So there is ambiguity regarding method of which Interface is being implemented by overriding.
Here I clear the ambiguity by calling super method myFun() by using super keyword and after super placing angular brackets and within the brackets mentioning the super Interface type - MyInterface1 or MyInterface2
Now the problem which arises here is that I can override either the myFun() method of Interface1 or of Interface2. But I can't call the myFun() method of both the Interfaces at the same time.
So is it possible to do any code tweak so that I can call myFun() method of both Interface1 and Interface2 at the same time?
A similar C# question already exists -
Inheritance from multiple interfaces with the same method name
But I am unable to implement the answers in Kotlin
Not quite sure that this is what you need, but you can use both super<MyInterface1>.myFun() and super<MyInterface2>.myFun() in the same myFun function
private class MyClass(override val val1: Int, override val val2: Int): MyInterface1, MyInterface2 {
override fun myFun() {
super<MyInterface1>.myFun()
super<MyInterface2>.myFun()
}
}
Answer provided by IR42 is good but the following approach suits me better -
class MyClass() {
class MyInnerClass1(override val val1: Int): MyInterface1 {
override fun myFun() {
super<MyInterface1>.myFun()
}
}
class MyInnerClass2(override val val2: Int): MyInterface2 {
override fun myFun() {
super<MyInterface2>.myFun()
}
}
}
Main function from where the two methods are called at the same time -
fun main() {
println(MyClass.MyInnerClass1(val1 = 1).myFun())
println(MyClass.MyInnerClass2(val2 = 2).myFun())
}
Is there any way to pass this when using interface delegation? This would enable nice composability - but I found no way to do this.
Means something like:
interface Foo {
}
class FooImpl(bar: Bar) : Foo {
}
class Bar: Foo by FooImpl(this) {
}
as long as FooImpl doesnt need a parameter like this it works - but it would be great to access the other class there - perhaps someone knows a way. Otherwise I would also be interested if this is worth a KEEP if not - or if it will be impossible for some reason.
Delegation doesn't support this. The delegate has to be instantiated before the class that is delegating to it, so the delegate cannot rely on it for construction. Another gotcha is that although you can override functions of the delegate, if the delegate internally calls those functions, it calls the original version, not the override. The delegate really lives in its own world.
But you could set it up for the host to pass itself to the delegate in its initialization block:
interface Foo<T> {
var host: T
fun doSomething()
}
class FooImpl : Foo<Bar> {
override lateinit var host: Bar
override fun doSomething() {
println(host.name)
}
}
class Bar(val name: String): Foo<Bar> by FooImpl() {
init {
host = this
}
}
fun main() {
val bar = Bar("Hello world")
bar.doSomething()
}
This would unfortunately expose the host to the possibility of getting disconnected from its own delegate by outside classes, though. Maybe you could make the property throw an exception if assigned more than once.
Here's a property delegate that could do that:
private class SingleAssignmentVar<T>: ReadWriteProperty<Any, T> {
private var value: T? = null
private var assigned: Boolean = false
#Suppress("UNCHECKED_CAST")
override fun getValue(thisRef: Any, property: KProperty<*>): T {
if (!assigned)
error("Property has not yet been set.")
return value as T
}
override fun setValue(thisRef: Any, property: KProperty<*>, value: T) {
if (assigned)
error("Property may only be set once.")
assigned = true
this.value = value
}
}
fun <T> Delegates.singleAssignment(): ReadWriteProperty<Any, T> = SingleAssignmentVar()
You may split your Bar class in two parts, say backend and frontend.
Frontend will be responsible for declaring interface with delegates, backend will host delegates and act as composition target.
For example:
interface Foo {
fun sayHello(): String
}
class FooImpl(val bar: BarBackend) : Foo {
override fun sayHello() = "Hello from ${bar.compositionTarget()}!"
}
class BarBackend() {
val fooImpl: FooImpl = FooImpl(this)
fun compositionTarget() = "backend"
}
class BarFrontend(backend: BarBackend) : Foo by backend.fooImpl
fun main() {
val bar = BarFrontend(BarBackend())
println(bar.sayHello())
}
I have just written this, which is fine as far as it goes:
import com.github.salomonbrys.kotson.get
import com.github.salomonbrys.kotson.int
import com.github.salomonbrys.kotson.jsonObject
import com.google.gson.JsonElement
import com.google.gson.JsonObject
abstract class BatchJobPayload {
abstract fun toJson(): JsonObject
}
class BookingConfirmationMessagePayload(val bookingId: Int) : BatchJobPayload() {
constructor(payload: JsonElement) : this(payload["bookingId"].int)
override fun toJson() = jsonObject(
"bookingId" to bookingId
)
}
But I'd like to insist, if possible, that all classes that extend BatchJobPayload implement a secondary constructor with the signature
constructor(payload: JsonElement): BatchJobPayload, which is to be used for deserializing.
BookingConfirmationMessagePayload has such a constructor but only because I put it there, not because BatchJobPayload insisted upon it...
A workable option I came up with as as follows:
interface BatchJobPayload {
fun toJson(): JsonObject
}
interface BatchJobPayloadDeserialize {
operator fun invoke(payload: JsonElement): BatchJobPayload
}
class BookingConfirmationMessagePayload(val bookingId: Int) : BatchJobPayload {
override fun toJson() = jsonObject(
"bookingId" to bookingId
)
}
class BookingConfirmationMessagePayloadDeserialize : BatchJobPayloadDeserialize {
override operator fun invoke(payload: JsonElement) =
BookingConfirmationMessagePayload(payload["bookingId"].int)
}
Now you can deserialize a BookingConfirmationMessagePayload object from a JsonElement as follows:
BookingConfirmationMessagePayloadDeserialize()(payload)
(The invoke operator is just some syntactic sugar here which may border on the obtuse...)
Actually I still prefer the original code which is less verbose --- a developer needing to subclass BatchJobPayload in the future may initially neglect to define a constructor that takes a JsonElement but they will surely realise their omission once they have just a string of JSON which they need to turn into an instance of their new class...
You can't enforce a super constructor, but you can have factories with a spawn method enforced that returns a subclass of BatchJobPayload, which allows you to make sure classes will be constructable.
It would look something like this:
class JsonObject // Included to make compiler happy
abstract class Factory<T> {
abstract fun make(obj: JsonObject): T
}
abstract class Base {
abstract fun toJson(): JsonObject
}
class A(val data:JsonObject):Base() {
override fun toJson(): JsonObject {
return JsonObject()
}
}
class AFactory: Factory<A>() {
override fun make(obj: JsonObject): A {
return A(obj)
}
}
fun main(args: Array<String>) {
val dummyJson = JsonObject()
var factory = AFactory()
var instance = factory.make(dummyJson)
println(instance)
}