forked from Kotlin/kotlinx.serialization
-
Notifications
You must be signed in to change notification settings - Fork 0
/
SerializationExceptions.kt
128 lines (115 loc) · 4.82 KB
/
SerializationExceptions.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/*
* Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.serialization
import kotlinx.serialization.encoding.*
/**
* A generic exception indicating the problem in serialization or deserialization process.
*
* This is a generic exception type that can be thrown during problems at any stage of the serialization,
* including encoding, decoding, serialization, deserialization, and validation.
* [SerialFormat] implementors should throw subclasses of this exception at any unexpected event,
* whether it is a malformed input or unsupported class layout.
*
* [SerializationException] is a subclass of [IllegalArgumentException] for the sake of consistency and user-defined validation:
* Any serialization exception is triggered by the illegal input, whether
* it is a serializer that does not support specific structure or an invalid input.
*
* It is also an established pattern to validate input in user's classes in the following manner:
* ```
* @Serializable
* class Foo(...) {
* init {
* required(age > 0) { ... }
* require(name.isNotBlank()) { ... }
* }
* }
* ```
* While clearly being serialization error (when compromised data was deserialized),
* Kotlin way is to throw `IllegalArgumentException` here instead of using library-specific `SerializationException`.
*
* For general "catch-all" patterns around deserialization of potentially
* untrusted/invalid/corrupted data it is recommended to catch `IllegalArgumentException` type
* to avoid catching irrelevant to serializaton errors such as `OutOfMemoryError` or domain-specific ones.
*/
public open class SerializationException : IllegalArgumentException {
/**
* Creates an instance of [SerializationException] without any details.
*/
public constructor()
/**
* Creates an instance of [SerializationException] with the specified detail [message].
*/
public constructor(message: String?) : super(message)
/**
* Creates an instance of [SerializationException] with the specified detail [message], and the given [cause].
*/
public constructor(message: String?, cause: Throwable?) : super(message, cause)
/**
* Creates an instance of [SerializationException] with the specified [cause].
*/
public constructor(cause: Throwable?) : super(cause)
}
/**
* Thrown when [KSerializer] did not receive a non-optional property from [CompositeDecoder] and [CompositeDecoder.decodeElementIndex]
* had already returned [CompositeDecoder.DECODE_DONE].
*
* [MissingFieldException] is thrown on missing field from all [auto-generated][Serializable] serializers and it
* is recommended to throw this exception from user-defined serializers.
*
* @see SerializationException
* @see KSerializer
*/
@ExperimentalSerializationApi
public class MissingFieldException(
missingFields: List<String>, message: String?, cause: Throwable?
) : SerializationException(message, cause) {
/**
* List of fields that were required but not found during deserialization.
* Contains at least one element.
*/
public val missingFields: List<String> = missingFields
/**
* Creates an instance of [MissingFieldException] for the given [missingFields] and [serialName] of
* the corresponding serializer.
*/
public constructor(
missingFields: List<String>,
serialName: String
) : this(
missingFields,
if (missingFields.size == 1) "Field '${missingFields[0]}' is required for type with serial name '$serialName', but it was missing"
else "Fields $missingFields are required for type with serial name '$serialName', but they were missing",
null
)
/**
* Creates an instance of [MissingFieldException] for the given [missingField] and [serialName] of
* the corresponding serializer.
*/
public constructor(
missingField: String,
serialName: String
) : this(
listOf(missingField),
"Field '$missingField' is required for type with serial name '$serialName', but it was missing",
null
)
@PublishedApi // Constructor used by the generated serializers
internal constructor(missingField: String) : this(
listOf(missingField),
"Field '$missingField' is required, but it was missing",
null
)
}
/**
* Thrown when [KSerializer] received unknown property index from [CompositeDecoder.decodeElementIndex].
*
* This exception means that data schema has changed in backwards-incompatible way.
*/
@PublishedApi
internal class UnknownFieldException
// This constructor is used by coroutines exception recovery
internal constructor(message: String?) : SerializationException(message) {
// This constructor is used by the generated serializers
constructor(index: Int) : this("An unknown field for index $index")
}