Add a less verbose error message to SerializationException
Use case: In my current use case, I am passing user-provided JSON input to the Json.decodeFromString function. In general, I expect this input to be erroneous. It could, for instance, contain a key that is not part of the actual data model. I want to make the user aware of such issues by printing a suitable error message.
Limitation: If I am not mistaken, the only possibility for me to detect such error conditions is by catching SerializationException. Unfortunately, the error message encoded into this Exception seems to be directed towards the developer and is not just objectively describing the issue. It looks as follows, for instance:
kotlinx.serialization.json.internal.JsonDecodingException: Unexpected JSON token at offset 4: Encountered
an unknown key 'name'. Use 'ignoreUnknownKeys = true' in 'Json {}' builder to ignore unknown keys.
JSON input: {
"name": "xyz"
}
Obviously, mentioning ignoreUnknownKeys to the user would be highly confusing.
Proposal: This specific problem could be solved by adding an optional SerializationException::shortMesssage property and populating it with error messages that focus solely on the client-controlled portions of the serialization/deserialization process (whenever this is applicable). Do you think this would be feasible? Or am I missing something here?
Alternatively, it might make sense to create public SerializationException subclasses that notify the caller about one specific error condition (such as the presence of an unknown field). This would probably be the cleanest and most flexible solution, but it would also require quite a bit of additional effort.
I think in your particular case it's easier to just do substring on the message. But in general, idea of messages/data addressed to the user may be interesting.
Thank you for your response.
I looked into the code that throws these Exceptions. Unfortunately, however, I was unable to recognize a "pattern" that I could use to parse the messages in a reasonable manner. Looking at code portions throwing JsonDecodingException, I can see that:
- JsonException.kt produces eight different kinds of error messages.
- TreeJsonDecoder.kt produces six additional messages.
- JsonElementSerializers.kt produces about three additional messages.
- TreeJsonEncoder.kt and Polymorphic.kt contribute to the message pool as well.
In addition, other kinds of Exceptions seem to be thrown as well, such as InvalidKeyKindException from here.
Do you have an idea of how a such a parsing strategy might look like?
For example in the MissingFieldException case the fields are hidden so as far as I can see it's pretty hard to even have a wrapper around that theoretically could do this type of post parsing production of more human readable messages.
I kind of like what it yields now and I would just like the possibility to use the class simple name instead of the fully qualified package and class name.
@dahankzter MissingFieldException is public from 1.4.0
I have this:
@PublishedApi
internal class MissingFieldException
// This constructor is used by coroutines exception recovery
internal constructor(message: String?, cause: Throwable?) : SerializationException(message, cause) {
// This constructor is used by the generated serializers
constructor(fieldName: String) : this("Field '$fieldName' is required, but it was missing", null)
internal constructor(fieldNames: List<String>, serialName: String) : this(if (fieldNames.size == 1) "Field '${fieldNames[0]}' is required for type with serial name '$serialName', but it was missing" else "Fields $fieldNames are required for type with serial name '$serialName', but they were missing", null)
}
But then again I am on 1.3.3... Any gotchas to upgrade?
Do you have an idea of how a such a parsing strategy might look like?
I would strongly avoid relying on the message parsing -- it's intended to be extensive, verbose and may change from version to version within patch releases. The parsing itself is rather a mean to address our lack of proper API to distinguish failure's reason.
It would be really helpful if you could list what exactly you are trying to achieve (e.g. what kinds of failures you are interested in, what kinds you are ignoring, what kind of additional information you would like to parse out etc.), so we can shape the API to be usable, future-proof and extensive enough for your use-cases
MissingFieldException in 1.4.1 (after some dependency wrangling in ktaor) works sort of for my case but it is still half baked for validations I would say. IT only exposes the fields that are missing but not the target class. I can parse the message but that quickly becomes cumbersome and hard to maintain.
I am actually doing this in a KTor project and if someone has already solved it for that case (nice non-nullable fields with as little as possible "external" validation) a pointer would be nice.
@qwwdfsad @dahankzter I think we can add serialName: String? too, because it is available in recent plugins.
That would be awesome! I can't speak for other cases but great for us.