10

Trying to deserialize cached json string to data object and getting exception: kotlinx.serialization.json.internal.JsonDecodingException: Expected class kotlinx.serialization.json.JsonObject (Kotlin reflection is not available) as the serialized body of kotlinx.serialization.Polymorphic<List>, but had class kotlinx.serialization.json.JsonArray (Kotlin reflection is not available)

Code used to deserialize

internal inline fun <reified R : Any> String.convertToDataClass() =
    Json {
        ignoreUnknownKeys = true
    }.decodeFromString(R::class.serializer(), this)

Code example:

val jsonString  ="""
[{"name1":"value1"}, {"name2":"value2"}]
"""
val dataObject = jsonString.convertToDataClass<List<SomeObject>>()

When going through Ktor pipeline everything works fine but it is breaking on attempt to deserialize the same response body cached as string.

I am aware of that R::class.serializer() is marked as for internal usage but this is the only way known to me how to deserialize generics from string content.

7
  • I'm not sure if this works but can you not reuse R as generic parameter for decodeFromString? Commented Jul 21, 2021 at 7:12
  • Hi @Dominik. You cannot pass R as a parameter if you're using Json class function decodeFromString. However, your question has led to me to find that StringFormat has extension function with same name but different definition, where you can pass R as a parameter. Switching to it, solved the error. Commented Jul 21, 2021 at 8:57
  • Why not? Do you really get a compiler error for Json.decodeFromString<R>(this)? Commented Jul 21, 2021 at 8:58
  • Yep, it expects two arguments. This is definition of the function fun <T> decodeFromString(deserializer: DeserializationStrategy<T>, string: String): T Commented Jul 21, 2021 at 9:00
  • 1
    Check github.com/Kotlin/…. The sample is val obj = Json.decodeFromString<Project>(string) so there should be a fitting overload. Commented Jul 21, 2021 at 9:01

1 Answer 1

15

There is a fitting extension function available at kotlinx.serialization.decodeFromString that takes one generic parameter, so you could pass R as generic to that extension.

Check https://github.com/Kotlin/kotlinx.serialization#introduction-and-references. The sample is val obj = Json.decodeFromString<Project>(string), which will fit your needs doing something like this

import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json    

internal inline fun <reified R : Any> String.convertToDataClass() =
    Json {
        ignoreUnknownKeys = true
    }.decodeFromString<R>(this)
Sign up to request clarification or add additional context in comments.

2 Comments

Please, add import statement to the answer import kotlinx.serialization.decodeFromString. Maybe somebody like me who uses explicit import statements are not aware of extension function.
Addition: I successfully used json.decodeFromString<List<String>>(myString) but then I realized, that there's no matching encodeToString function. But I found this solution: json.encodeToString(serializer<List<LastAdminAction>>(), myList) with import kotlinx.serialization.serializer

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.