Bitwise DEVS
Bitwise DEVS

Reputation: 3449

Kotlin: Cannot convert Map to JSON

How to convert Map to JSONObject? It accepts Map but it seems you need to perform casting. Is there any other way to do this without using library?

enter image description here

Upvotes: 0

Views: 425

Answers (2)

Karsten Gabriel
Karsten Gabriel

Reputation: 3662

The answer provided by Bitwise DEVS may work, but the explanation is incorrect.

It is not necessary to convert the map into an immutable map - it can even be seen in the screenshot of the question: expected (Mutable)Map means that it can be mutable or immutable.

The real problem here is that the called constructor of JSONObject is defined for Map<Any?, Any?> but the given parameter is of type Map<String!, String!>. We know that String is a subtype of Any?, so why is that a problem?

It is a problem because Map is invariant in the key parameter which means that a Map<A, V> is not subtype of Map<B, V> even if A is subtype of B (and also not if it is the other way around).

The call of toMap does not work because it makes the map immutable, but because it is defined as

fun <K, V> Map<out K, V>.toMap(): Map<K, V>

In the receiver type of toMap the key parameter is annotated with the out modifier, meaning that K is covariant here. This means that a Map<Any, V> in this position can safely be considered as a supertype of Map<String, V>. Additionally, Map is always covariant in its value type, meaning that Map<Any, Any> in this position can safely be considered as a supertype of Map<String, String>.

You could as well just cast remoteMessage.data as Map<Any?, Any?> or use toMutableMap, it would be all the same. It has definitely nothing to do with mutability of the map.

Kotlin documentation on variance: https://kotlinlang.org/docs/generics.html#declaration-site-variance

Kotlin documentation of Map: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-map/

Definition of toMap: https://github.com/JetBrains/kotlin/blob/ea836fd46a1fef07d77c96f9d7e8d7807f793453/libraries/stdlib/src/kotlin/collections/Maps.kt#L600

Upvotes: 3

Bitwise DEVS
Bitwise DEVS

Reputation: 3449

I just realized the answer, if you are using Map like Map<String, String> in Kotlin there is a mutable and immutable version of it. In the question above all you need to do is to convert it to immutable Map using toMap().

val msgData = parser.fromJsonString<CommonNotification>(
            JSONObject(remoteMessage.data.toMap()).toString(),
            CommonNotification::class.java
        ) ?: return

Upvotes: 1

Related Questions