Open yackermann opened 4 years ago
Same thing with ints to strings
Please, check out isLenient
setting for JSON. https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/json.md#lenient-parsing
Does it do what you need?
@elizarov isLenient makes parser more flexible. For my project I need strict parsing.
I have tested with isLinient = false, and it produces the same result. *(
Thanks! Now I see what you want. Why do you want it, though? What's wrong with accepting "22"
for an integer in your case?
@elizarov FIDO protocols require strict JSON parsing to get certification.
What else? Where can we read more?
What @elizarov what do you mean?
There are a lot of standards that require strict parsing of JSON for compliancy and certification.
Can you, please, provide a link to such a standard to make sure we can study it and see what else we might be missing for compliance.
@herrjemand could you please also elaborate on what you have been using prior to kotlinx-serialization? I've checked Moshi, GSON and Jackson, none of them supports this functionality by default.
Jackson will provide CoercionConfig
in the next release that supports a lot of various coercion strategies, but for now it's unavailable
@qwwdfsad Actually, while trying to switch from Jackson to kotlinx.serialisation, I found one of my test cases broke due to this. Jackson does in fact, not allow strings to be treated as integers (as expected).
I'm interested too in this feature. The reason: I have non-JSON documents i first transform to a JSON string and feed those to kotlinx.serialization. Hence all primitives are strings. The best place to coerce them in Json.decodeFromString<MyDto>(json)
as that function knows the target types in MyDto
I actually have a non-Json case where I'd like coercion. I'm using the Properties module to turn maps into objects but unfortunately my maps are Map<String, String>
not Map<String, Any>
.
@Serializable
data class Foo(val n: Int)
val map = mapOf("n" to "5") // this actually comes from external source, I do not have control of types
Properties.decodeFromMap(Foo.serializer(), map) // throws ClassCastException
java.lang.ClassCastException: class java.lang.String cannot be cast to class java.lang.Integer (java.lang.String and java.lang.Integer are in module java.base of loader 'bootstrap')
at kotlinx.serialization.internal.TaggedDecoder.decodeTaggedInt(Tagged.kt:195)
at kotlinx.serialization.internal.TaggedDecoder.decodeInt(Tagged.kt:226)
at kotlinx.serialization.internal.IntSerializer.deserialize(Primitives.kt:125)
at kotlinx.serialization.internal.IntSerializer.deserialize(Primitives.kt:121)
at kotlinx.serialization.properties.Properties$InMapper.decodeSerializableValue(Properties.kt:114)
at kotlinx.serialization.internal.TaggedDecoder.decodeSerializableValue(Tagged.kt:207)
at kotlinx.serialization.internal.TaggedDecoder$decodeNullableSerializableElement$1.invoke(Tagged.kt:288)
at kotlinx.serialization.internal.TaggedDecoder.tagBlock(Tagged.kt:294)
at kotlinx.serialization.internal.TaggedDecoder.decodeNullableSerializableElement(Tagged.kt:286)
Workaround is to create a new custom Serializer and annotate. Would be nice to have something built in for this though.
object IntAsStringSerializer : KSerializer<Int> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("IntAsString", PrimitiveKind.STRING)
override fun serialize(encoder: Encoder, value: Int) {
encoder.encodeString(value.toString())
}
override fun deserialize(decoder: Decoder): Int {
val stringValue = decoder.decodeString()
return stringValue.toIntOrNull() ?: throw SerializationException("Cannot parse int from string")
}
}
Also #2696
Describe the bug
When requiring type of Int in a serializable class, type coerce string to int without throwing an error.
To Reproduce Attach a code snippet or test data if possible.
Expected behavior
EXCEPTION
Environment