Kotlinx.serialization part2
This is a series, you can find the first part of the story:
In the part1 article I have written about basic of the kotlinx.serialization.
As you know when you want to serialize or deserialize an object then we need a Json object. What is this ?
- Json is a configuration holder object
If you search in the Internet you can find a lot of article where there is a different syntax (JSON, or JsonConfiguration). The reason is API change in the RC release. :( Earlier there was a public JsonConfiguration object which is now private and there is a builder if you want to set some configuration variable.
Json {
encodeDefaults = true
ignoreUnknownKeys = true
isLenient = true
allowStructuredMapKeys = true
prettyPrint = true
prettyPrintIndent = " "
coerceInputValues = true
useArrayPolymorphism = true
classDiscriminator = ""
allowSpecialFloatingPointValues = true
serializersModule = SerializersModule { }
}
You can find the documentation here:
encodeDefaults
By default kotlinx will not encode the default value(s).
@Serializable
data class Data(val text: String? = null, val text2: String? = null, val text3: String = "foo")val data = Data()val encodedString = Json.encodeToString(data)
If you print encodedString it will be { }. Ok, when we deserialize it -> it will be same object however sometimes we need the null value (e.g. our backend will handle it)
Solution:
val encodedString = Json { encodeDefaults = true }.encodeToString(data)
The result will be: {“text”:null,”text2":null,”text3":”foo”}
ignoreUnknownKeys
JSON format often is used in network communication. It is a common use case we have an object in our application and it has been changed in current version of the network call. (Object version is changed on backend)
@Serializable
data class Data(val userName: String)val obj = Json.decodeFromString<Data>("{\"userName\": \"fooUser\", \"city\": \"Budapest\"}")
If we run the code above then we will get an exception:
kotlinx.serialization.json.internal.JsonDecodingException: Unexpected JSON token at offset 42: Encountered an unknown key 'city'.
Use 'ignoreUnknownKeys = true' in 'Json {}' builder to ignore unknown keys.
JSON input: {"userName": "fooUser", "city": "Budapest"}
The error message will show the solution we need to turn on ignoreUnknownKeys setting to parse the object.
isLenient
By default there are some restriction in JSON format (https://www.ietf.org/rfc/rfc4627.txt). Keys must be quoted, literals shall be unquoted.
Can we parse this string “{userName: fooUser}” ?
With help of isLenient we are able to parse a string much more flexibility.
@Serializable
data class Data(val userName: String)Json { isLenient = true }.decodeFromString<Data>("{userName: fooUser}")
Without this settings we will get an exception:
kotlinx.serialization.json.internal.JsonDecodingException: Unexpected JSON token at offset 1: Expected string literal with quotes.
Use 'isLenient = true' in 'Json {}` builder to accept non-compliant JSON.
JSON input: {userName: fooUser}
allowStructuredMapKeys
By default JSON format do not allow to use map with structured map.
@Serializable
data class Data(val userName: String)Json.encodeToString(mapOf(Data("test") to 1, Data("testX") to 2))
If we want to encode a map with object type key (structured object) we need to set allowStructuredMapKeys settings.
prettyPrint
Sometimes we want to see a well readable JSON instead of one line of String. With help of prettyPrint settings we will get a human readable text. By default there will be 4 spaces indent. If we want to setup different indention we can set with prettyPrintIndent option.
This option could be very useful when we want to print a JSON string in a log file or Logcat.
coerceInputValues
Kotlin has some very useful language feature like default value. This feature will help us to avoid to use null value like a valid value. Ok, and how can we use this feature when backend can send us null value?
@Serializable
data class Data(val userName: String, val city: String = "nowhere")val data = Json.decodeFromString<Data>("{\"userName\": \"test\", \"city\": null}")val data2 = Json.decodeFromString<Data>("{\"userName\": \"test\"}")
The second object data2 will be parsed successful and city will hold the default value as we expected. However the first object (data) will cause an exception because there is a null type in the JSON. If we want to avoid this kind of exception we need to set coerceInputValues = true.
allowSpecialFloatingPointValues
By default JSON do not support special floating point values like NaN (Not a Number) or infinities.
@Serializable
data class Data(val number: Double)Json { allowSpecialFloatingPointValues = true }.encodeToString(Data(Double.NaN))
And the result will be: {“number”:NaN}
In next part I will write about how can we parse some extra data object like Date or BigDecimal:
If you found this post useful? Kindly tap the 👏 button below and follow, thanks! :)