• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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