1 /*
2 * Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3 */
4 @file:OptIn(ExperimentalSerializationApi::class)
5
6 package kotlinx.serialization.json
7
8 import kotlinx.serialization.*
9 import kotlinx.serialization.builtins.*
10 import kotlinx.serialization.descriptors.*
11 import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
12 import kotlinx.serialization.encoding.*
13 import kotlinx.serialization.json.internal.JsonDecodingException
14
15 /**
16 * Serializer object providing [SerializationStrategy] and [DeserializationStrategy] for [JsonElement].
17 * It can only be used by with [Json] format and its input ([JsonDecoder] and [JsonEncoder]).
18 * Currently, this hierarchy has no guarantees on descriptor content.
19 *
20 * Example usage:
21 * ```
22 * val string = Json.encodeToString(JsonElementSerializer, json { "key" to 1.0 })
23 * val literal = Json.decodeFromString(JsonElementSerializer, string)
24 * assertEquals(JsonObject(mapOf("key" to JsonLiteral(1.0))), literal)
25 * ```
26 */
27 @PublishedApi
28 internal object JsonElementSerializer : KSerializer<JsonElement> {
29 override val descriptor: SerialDescriptor =
<lambda>null30 buildSerialDescriptor("kotlinx.serialization.json.JsonElement", PolymorphicKind.SEALED) {
31 // Resolve cyclic dependency in descriptors by late binding
32 element("JsonPrimitive", defer { JsonPrimitiveSerializer.descriptor })
33 element("JsonNull", defer { JsonNullSerializer.descriptor })
34 element("JsonLiteral", defer { JsonLiteralSerializer.descriptor })
35 element("JsonObject", defer { JsonObjectSerializer.descriptor })
36 element("JsonArray", defer { JsonArraySerializer.descriptor })
37 }
38
serializenull39 override fun serialize(encoder: Encoder, value: JsonElement) {
40 verify(encoder)
41 when (value) {
42 is JsonPrimitive -> encoder.encodeSerializableValue(JsonPrimitiveSerializer, value)
43 is JsonObject -> encoder.encodeSerializableValue(JsonObjectSerializer, value)
44 is JsonArray -> encoder.encodeSerializableValue(JsonArraySerializer, value)
45 }
46 }
47
deserializenull48 override fun deserialize(decoder: Decoder): JsonElement {
49 val input = decoder.asJsonDecoder()
50 return input.decodeJsonElement()
51 }
52 }
53
54 /**
55 * Serializer object providing [SerializationStrategy] and [DeserializationStrategy] for [JsonPrimitive].
56 * It can only be used by with [Json] format an its input ([JsonDecoder] and [JsonEncoder]).
57 */
58 @PublishedApi
59 internal object JsonPrimitiveSerializer : KSerializer<JsonPrimitive> {
60 override val descriptor: SerialDescriptor =
61 buildSerialDescriptor("kotlinx.serialization.json.JsonPrimitive", PrimitiveKind.STRING)
62
serializenull63 override fun serialize(encoder: Encoder, value: JsonPrimitive) {
64 verify(encoder)
65 return if (value is JsonNull) {
66 encoder.encodeSerializableValue(JsonNullSerializer, JsonNull)
67 } else {
68 encoder.encodeSerializableValue(JsonLiteralSerializer, value as JsonLiteral)
69 }
70 }
71
deserializenull72 override fun deserialize(decoder: Decoder): JsonPrimitive {
73 val result = decoder.asJsonDecoder().decodeJsonElement()
74 if (result !is JsonPrimitive) throw JsonDecodingException(-1, "Unexpected JSON element, expected JsonPrimitive, had ${result::class}", result.toString())
75 return result
76 }
77 }
78
79 /**
80 * Serializer object providing [SerializationStrategy] and [DeserializationStrategy] for [JsonNull].
81 * It can only be used by with [Json] format an its input ([JsonDecoder] and [JsonEncoder]).
82 */
83 @PublishedApi
84 internal object JsonNullSerializer : KSerializer<JsonNull> {
85 // technically, JsonNull is an object, but it does not call beginStructure/endStructure at all
86 override val descriptor: SerialDescriptor =
87 buildSerialDescriptor("kotlinx.serialization.json.JsonNull", SerialKind.ENUM)
88
serializenull89 override fun serialize(encoder: Encoder, value: JsonNull) {
90 verify(encoder)
91 encoder.encodeNull()
92 }
93
deserializenull94 override fun deserialize(decoder: Decoder): JsonNull {
95 verify(decoder)
96 if (decoder.decodeNotNullMark()) {
97 throw JsonDecodingException("Expected 'null' literal")
98 }
99 decoder.decodeNull()
100 return JsonNull
101 }
102 }
103
104 private object JsonLiteralSerializer : KSerializer<JsonLiteral> {
105
106 override val descriptor: SerialDescriptor =
107 PrimitiveSerialDescriptor("kotlinx.serialization.json.JsonLiteral", PrimitiveKind.STRING)
108
109 @OptIn(ExperimentalSerializationApi::class)
serializenull110 override fun serialize(encoder: Encoder, value: JsonLiteral) {
111 verify(encoder)
112 if (value.isString) {
113 return encoder.encodeString(value.content)
114 }
115
116 if (value.coerceToInlineType != null) {
117 return encoder.encodeInline(value.coerceToInlineType).encodeString(value.content)
118 }
119
120 // use .content instead of .longOrNull as latter can process exponential notation,
121 // and it should be delegated to double when encoding.
122 value.content.toLongOrNull()?.let { return encoder.encodeLong(it) }
123
124 // most unsigned values fit to .longOrNull, but not ULong
125 value.content.toULongOrNull()?.let {
126 encoder.encodeInline(ULong.serializer().descriptor).encodeLong(it.toLong())
127 return
128 }
129
130 value.content.toDoubleOrNull()?.let { return encoder.encodeDouble(it) }
131 value.content.toBooleanStrictOrNull()?.let { return encoder.encodeBoolean(it) }
132
133 encoder.encodeString(value.content)
134 }
135
deserializenull136 override fun deserialize(decoder: Decoder): JsonLiteral {
137 val result = decoder.asJsonDecoder().decodeJsonElement()
138 if (result !is JsonLiteral) throw JsonDecodingException(-1, "Unexpected JSON element, expected JsonLiteral, had ${result::class}", result.toString())
139 return result
140 }
141 }
142
143 /**
144 * Serializer object providing [SerializationStrategy] and [DeserializationStrategy] for [JsonObject].
145 * It can only be used by with [Json] format an its input ([JsonDecoder] and [JsonEncoder]).
146 */
147 @PublishedApi
148 internal object JsonObjectSerializer : KSerializer<JsonObject> {
149
<lambda>null150 private object JsonObjectDescriptor : SerialDescriptor by MapSerializer(String.serializer(), JsonElementSerializer).descriptor {
151 @ExperimentalSerializationApi
152 override val serialName: String = "kotlinx.serialization.json.JsonObject"
153 }
154
155 override val descriptor: SerialDescriptor = JsonObjectDescriptor
156
serializenull157 override fun serialize(encoder: Encoder, value: JsonObject) {
158 verify(encoder)
159 MapSerializer(String.serializer(), JsonElementSerializer).serialize(encoder, value)
160 }
161
deserializenull162 override fun deserialize(decoder: Decoder): JsonObject {
163 verify(decoder)
164 return JsonObject(MapSerializer(String.serializer(), JsonElementSerializer).deserialize(decoder))
165 }
166 }
167
168 /**
169 * Serializer object providing [SerializationStrategy] and [DeserializationStrategy] for [JsonArray].
170 * It can only be used by with [Json] format an its input ([JsonDecoder] and [JsonEncoder]).
171 */
172 @PublishedApi
173 internal object JsonArraySerializer : KSerializer<JsonArray> {
174
<lambda>null175 private object JsonArrayDescriptor : SerialDescriptor by ListSerializer(JsonElementSerializer).descriptor {
176 @ExperimentalSerializationApi
177 override val serialName: String = "kotlinx.serialization.json.JsonArray"
178 }
179
180 override val descriptor: SerialDescriptor = JsonArrayDescriptor
181
serializenull182 override fun serialize(encoder: Encoder, value: JsonArray) {
183 verify(encoder)
184 ListSerializer(JsonElementSerializer).serialize(encoder, value)
185 }
186
deserializenull187 override fun deserialize(decoder: Decoder): JsonArray {
188 verify(decoder)
189 return JsonArray(ListSerializer(JsonElementSerializer).deserialize(decoder))
190 }
191 }
192
verifynull193 private fun verify(encoder: Encoder) {
194 encoder.asJsonEncoder()
195 }
196
verifynull197 private fun verify(decoder: Decoder) {
198 decoder.asJsonDecoder()
199 }
200
asJsonDecodernull201 internal fun Decoder.asJsonDecoder(): JsonDecoder = this as? JsonDecoder
202 ?: throw IllegalStateException(
203 "This serializer can be used only with Json format." +
204 "Expected Decoder to be JsonDecoder, got ${this::class}"
205 )
206
207 internal fun Encoder.asJsonEncoder() = this as? JsonEncoder
208 ?: throw IllegalStateException(
209 "This serializer can be used only with Json format." +
210 "Expected Encoder to be JsonEncoder, got ${this::class}"
211 )
212
213
214 /**
215 * Returns serial descriptor that delegates all the calls to descriptor returned by [deferred] block.
216 * Used to resolve cyclic dependencies between recursive serializable structures.
217 */
218 @OptIn(ExperimentalSerializationApi::class)
219 private fun defer(deferred: () -> SerialDescriptor): SerialDescriptor = object : SerialDescriptor {
220
221 private val original: SerialDescriptor by lazy(deferred)
222
223 override val serialName: String
224 get() = original.serialName
225 override val kind: SerialKind
226 get() = original.kind
227 override val elementsCount: Int
228 get() = original.elementsCount
229
230 override fun getElementName(index: Int): String = original.getElementName(index)
231 override fun getElementIndex(name: String): Int = original.getElementIndex(name)
232 override fun getElementAnnotations(index: Int): List<Annotation> = original.getElementAnnotations(index)
233 override fun getElementDescriptor(index: Int): SerialDescriptor = original.getElementDescriptor(index)
234 override fun isElementOptional(index: Int): Boolean = original.isElementOptional(index)
235 }
236