How to handle optional/default values with a more advanced serializer?
See original GitHub issueTo the point: I need to take a JSON input like { "number": { "innerNumber": 4 } }
, and parse it into a top-level number
property (like the input were { "number": 4 }
.
Therefore, I implemented the serializer like this:
object TestSerializer : KSerializer<Int?> {
override val descriptor = PrimitiveDescriptor("Test", PrimitiveKind.INT)
override fun deserialize(decoder: Decoder) =
(decoder as JsonInput).decodeJson().jsonObject.getPrimitiveOrNull("innerNumber")?.intOrNull
override fun serialize(encoder: Encoder, value: Int?) =
(encoder as JsonOutput).encodeJson(json { "innerNumber" to value })
}
… along with my data holder:
@Serializable
data class TestData(
@Serializable(with = TestSerializer::class)
val number: Int? = -1
)
Notice the default value of -1
.
If I feed it with a valid JSON input, it works flawlessly:
fun main() {
val input = """{ "number": { "innerNumber": 324 } } """
val output = Json(JsonConfiguration.Stable).parse(TestData.serializer(), input)
println(output) // Prints TestData(number = 324)
}
However, let’s suppose that I get a malformed JSON as input, like { "number": { } }
. In this case, I get TestData(number = null)
– because it identified that the number
property exists, and, therefore, called the deserialize
method of my custom serializer, which returns null if it couldn’t find innerNumber
inside the JSON.
How can I indicate/notify the decoder, that, even though a property with the same name (number
) exists, its decoding/parsing failed, and it should fallback to the default value?
Issue Analytics
- State:
- Created 4 years ago
- Comments:12 (6 by maintainers)
Top GitHub Comments
@Elvis10ten The problem is that the format/nor descriptor is able to know whether the value is default or what the default value is. Normally this is encoded in the generated serializer, but if you make a custom serializer you will have to do that by hand.
If you want more complex behaviour, what you do is create a separate (nested private) class for (de)serialization, delegate the de(serialization) to the serializer for that class, and then generate the actual model from that (with more complex rules/behaviour).
Use case: Protobuf schema generator cannot generate message schema correctly with fields that have non-type-specific default values in kotlin codes. But protobuf itself has had support default value for fields. The only limitation is that we cannot get the default value from SerialDescriptor interface.