Parcelable overload resolution ambiguity - kotlin

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.

Related

Dagger and Kotlin - Issue with binding a class to its generic supertype

I'm banging my head against the wall right now because I can't figure this out.
I have a generic Interface called Mapper which has two generic type parameters. Now I want to leverage multibinding and bind multiple implementations of this interface into a map of type Map<Class<out Any>, Provider<Mapper<Any, Any>>. My code looks as follows:
interface Mapper<DTO, Entity> {
fun toEntity(model: DTO): Entity
fun toDto(model: Entity): DTO
}
class PersistedIntakeEntryMapper #Inject constructor() : Mapper<PersistedIntakeEntry, IntakeEntry> {
override fun toEntity(model: PersistedIntakeEntry): IntakeEntry { TODO() }
override fun toDto(model: IntakeEntry): PersistedIntakeEntry { TODO() }
}
#Module
interface MapperModule {
#Binds
#IntoMap
#MapperKey(PersistedIntakeEntry::class)
#ModelMappers
fun bindPersistedIntakeEntryMapper(mapper: PersistedIntakeEntryMapper): Mapper<Any, Any>
}
#Singleton
class MapperFactory #Inject constructor(
#ModelMappers val mappers: Map<Class<out Any>, #JvmSuppressWildcards Provider<Mapper<Any, Any>>>,
) {
#Suppress("UNCHECKED_CAST")
inline fun <reified DTO: Any, Entity> get(): Mapper<DTO, Entity>? {
TODO()
}
}
Dagger is specifically complaining that PersistedIntakeEntryMapper is not assignable to Mapper<Any, Any>: MapperModule.java:13: error: #Binds methods' parameter type must be assignable to the return type.
However: the curious thing is that I have the same setup for another component which works like a charm:
interface ViewModelFactory<VM : ViewModel, SavedState, Parameters> {
fun create(savedState: SavedState?, parameters: Parameters?): VM
}
class SetCalorieGoalViewModelFactory #Inject constructor(
private val getCalorieGoalUseCase: GetCalorieGoalUseCase,
private val setCalorieGoalUseCase: SetCalorieGoalUseCase,
private val navigator: Navigator,
) : ViewModelFactory<SetCalorieGoalViewModel, SetCalorieGoalUiState, Nothing> {
override fun create(savedState: SetCalorieGoalUiState?, parameters: Nothing?): SetCalorieGoalViewModel {
TODO()
}
}
#Module
interface SetCalorieGoalUiModule {
#Binds
#IntoMap
#ViewModelKey(SetCalorieGoalViewModel::class)
fun bindSetCalorieGoalViewModelFactory(factory: SetCalorieGoalViewModelFactory)
: ViewModelFactory<ViewModel, Any, Any>
}
I can bind the SetCalorieGoalViewModelFactory to the ViewModelFactory<SetCalorieGoalViewModel, Any, Any> type without issue. What is the difference between these setups that makes one of them work and the other one not? I can't figure it out for the life of me. Big thanks in advance to anyone trying to solve this problem.
First of all, check out kotlin documentation on the generic variance topic as well as the related java topics (since dagger generates java code).
Generally the issue is that Mapper<PersistedIntakeEntry, IntakeEntry> and Mapper<Any, Any> are invariant, meaning that one is not subtype of the other. Basically this assignment val mapper: Mapper<Any, Any> = PersistedIntakeEntryMapper() will not compile and that's what dagger tells you. And that makes sense, since Mapper<Any, Any> must be able to map Any to Any and that's obviously not the case with PersistedIntakeEntryMapper - it expects PersistedIntakeEntry and IntakeEntry.
Following the documentation above, it would be possible if your declaration had out modifier specified like interface Mapper<out DTO, out Entity>, but that will not work in your case, since you have your type arguments in in positions.
The interesting question is why it works with ViewModelFactory. It seems to be a bug in KAPT, it just omits generic type parameters in the generated code when it sees Nothing. It makes it bypass the compiler checks (but it does not make it safe to use at runtime!), since generics are mostly compile-time things (see type erasure in java).

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

Can I omit type in generics? - Kotlin

If I have a following interface:
interface BaseDataRemote<T, in Params> {
fun getData(params: Params? = null): Single<T>
}
Would it be possible have implementation of this interface that does not take Params?
To have effectively something like:
interface BaseDataRemote<T> {
fun getData(): Single<T>
}
Implementation is as follows:
class RemoteSellerDataSource #Inject constructor(
private val sellerApi: SellerApi,
#Named("LANG") private val lang: String
) : BaseDataRemote<SellerEntity, Nothing> {
override fun getData(params: Nothing?): Single<SellerEntity> {
return sellerApi.getSeller(lang).map { it.fromApiEntity() }
}
}
I use Dagger 2 to module to bind this implementation:
#Module
internal interface RemoteModule {
#Binds
#CoreScope
fun bindsSellerRemote(remoteSellerDataSource: RemoteSellerDataSource): BaseDataRemote<SellerEntity, Nothing>
}
I tried using Nothing as second type parameter, but it does not seem to work
(I'm getting required: class or interface without bounds error
Full error message:
RemoteSellerDataSource.java:6: error: unexpected type
public final class RemoteSellerDataSource implements com.bigchangedev.stamps.business.sdk.data.base.data.BaseDataRemote<SellerEntity, ?> {
^
required: class or interface without bounds
found:?
Thanks.
EDIT: the original answer was a pure Kotlin answer because the OP didn't mention Dagger.
Using Nothing is correct and works in pure Kotlin. However, Dagger seems to convert your code to Java, and in doing so it uses wildcards for the generics (which it doesn't like because it wants exact type matches). To avoid this issue, you can try using #JvmSuppressWildcards on your generic type parameters:
class RemoteSellerDataSource #Inject constructor(
private val sellerApi: SellerApi,
#Named("LANG") private val lang: String
) : BaseDataRemote<SellerEntity, #JvmSuppressWildcards Nothing> {
override fun getData(params: Nothing?): Single<SellerEntity> {
return sellerApi.getSeller(lang).map { it.fromApiEntity() }
}
}
Although I'm not sure what will happen in Java with Nothing in that case. I guess this should have the same effect on the Java code as removing the in variance for the second type param in the interface declaration, but without weakening your Kotlin types.
Another workaround would be to use Unit instead of Nothing, which Dagger will most likely convert to Void in this case. This is not great for your types, though.
Original answer:
You can technically already call getData() without arguments thanks to the default value. An implementation that doesn't care about the params argument can simply expect null all the time.
The Kotlin type that only contains null and no other value is technically Nothing?, and since getData is defined with Params? (note the ?) as input, it should be correct to specify Nothing (even without ?) as second type argument. So you should be able to define an implementation like this:
interface BaseDataRemote<T, in Params> {
fun getData(params: Params? = null): Single<T>
}
class ImplementationWithoutParams<T> : BaseDataRemote<T, Nothing> {
override fun getData(params: Nothing?): Single<T> {
// params will always be null here
}
}
To avoid confusion for the users, this implementation may additionally provide a getData() method without arguments at all:
class ImplementationWithoutParams<T> : BaseDataRemote<T, Nothing> {
override fun getData(params: Nothing?): Single<T> = getData()
fun getData(): Single<T> {
TODO("implementation")
}
}

Kotlin class generics without duplication

Consider an abstract class:
abstract class PubSubSubscriber<T : Any>(private val topic: KClass<T>) : BackgroundFunction<PubSubMessage> {
abstract fun consume(payload: T)
override fun accept(message: PubSubMessage, context: Context) {
val json = String(Base64.getDecoder().decode(message.data.toByteArray()))
val payload = objectMapper.readValue(json, topic.java)
consume(payload)
}
}
And implementation:
class MySubscriber : PubSubSubscriber<Payload>(Payload::class) {
Is there a way to define such abstract class so that I don't have to repeat twice the Payload and Payload::class in the class definition?
Yes, with some reflection.
At construction time, we can extract the type parameter and assign it to a property that no longer needs to be given to the constructor:
abstract class PubSubSubscriber<T : Any> {
val topic: KClass<T> = extractTypeParam<T>(0).kotlin
private fun <X> extractTypeParam(paramIdx: Int): Class<X> {
require(PubSubSubscriber::class.java == javaClass.superclass) {
"PubSubSubscriber subclass $javaClass should directly extend PubSubSubscriber"
}
#Suppress("UNCHECKED_CAST")
return (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[paramIdx] as Class<X>
}
abstract fun consume(payload: T)
override fun accept(message: PubSubMessage, context: Context) {
val json = String(Base64.getDecoder().decode(message.data.toByteArray()))
val payload = objectMapper.readValue(json, topic.java)
consume(payload)
}
Note the following limitations:
A) this solution works only if MySubscriber directly extends from PubSubSubscriber. However, the given code can detect if that's not the case and warn about it (at runtime). In such cases, there are the following solutions:
MySubscriber falls back to providing a duplicate argument (essentially what you already had)
the direct superclass of MySubscriber can provide a similar detection mechanism
B) You call reflection code every time a MySubscriber instance is created. This may be too slow in certain contexts, but for many this is unproblematic.

Kotlin Inheritance - Extend JVM class and interface which have same method names

I have a custom Exception class which looks like this:
class GenericException(message: String?, errorCode: Int) : RuntimeException(message), GraphQLError {
.....
}
As you all know, RuntimeException extends Throwable which has a method called getMessage()
Now the issue is, this interface GraphQLError (which is a library interface) also has a method called getMessage()
As a result, compiler is complaining with this:
OK so I implement the method:
override fun getMessage(): String {
TODO("Not yet implemented")
}
Now I get this:
What am I supposed to do here?
What I guessed in the comments was right, kotlin allows multiple inheritence. It was indeed because of the Throwable class.
You can use #JvmField annotation to instruct the compiler not to generate getters and setters for the field and then create the getter/setter yourself.
interface HasMessage {
fun getMessage(): String
}
class GenericException(
#JvmField override val message: String?, // var is also possible
val errorCode: Int // I made it a property, might not be as well
) : RuntimeException(message), HasMessage {
override fun getMessage(): String {
// return of the super's getter, probably no use because you have field as property in this class
val superGetMessage = super<RuntimeException>.message
TODO("Not yet implemented")
}
}
Play with the code yourself.