1 /*
2  * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3  */
4 
5 package kotlinx.serialization.json
6 
7 import kotlinx.serialization.encoding.*
8 
9 /**
10  * Encoder used by [Json] during serialization.
11  * This interface can be used to inject desired behaviour into a serialization process of [Json].
12  *
13  * Typical example of the usage:
14  * ```
15  * // Class representing Either<Left|Right>
16  * sealed class Either {
17  *     data class Left(val errorMsg: String) : Either()
18  *     data class Right(val data: Payload) : Either()
19  * }
20  *
21  * // Serializer injects custom behaviour by inspecting object content and writing
22  * object EitherSerializer : KSerializer<Either> {
23  *     override val descriptor: SerialDescriptor = buildSerialDescriptor("package.Either", PolymorphicKind.SEALED) {
24  *          // ..
25  *      }
26  *
27  *     override fun deserialize(decoder: Decoder): Either {
28  *         val input = decoder as? JsonDecoder ?: throw SerializationException("This class can be decoded only by Json format")
29  *         val tree = input.decodeJsonElement() as? JsonObject ?: throw SerializationException("Expected JsonObject")
30  *         if ("error" in tree) return Either.Left(tree["error"]!!.jsonPrimitive.content)
31  *         return Either.Right(input.json.decodeFromJsonElement(Payload.serializer(), tree))
32  *     }
33  *
34  *     override fun serialize(encoder: Encoder, value: Either) {
35  *         val output = encoder as? JsonEncoder ?: throw SerializationException("This class can be encoded only by Json format")
36  *         val tree = when (value) {
37  *           is Either.Left -> JsonObject(mapOf("error" to JsonPrimitve(value.errorMsg)))
38  *           is Either.Right -> output.json.encodeToJsonElement(Payload.serializer(), value.data)
39  *         }
40  *         output.encodeJsonElement(tree)
41  *     }
42  * }
43  * ```
44  *
45  * ### Not stable for inheritance
46  *
47  * `JsonEncoder` interface is not stable for inheritance in 3rd party libraries, as new methods
48  * might be added to this interface or contracts of the existing methods can be changed.
49  * Accepting this interface in your API methods, casting [Encoder] to [JsonEncoder] and invoking its
50  * methods is considered stable.
51  */
52 public interface JsonEncoder : Encoder, CompositeEncoder {
53     /**
54      * An instance of the current [Json].
55      */
56     public val json: Json
57 
58     /**
59      * Appends the given JSON [element] to the current output.
60      * This method is allowed to invoke only as the part of the whole serialization process of the class,
61      * calling this method after invoking [beginStructure] or any `encode*` method will lead to unspecified behaviour
62      * and may produce an invalid JSON result.
63      * For example:
64      * ```
65      * class Holder(val value: Int, val list: List<Int>())
66      *
67      * // Holder serialize method
68      * fun serialize(encoder: Encoder, value: Holder) {
69      *     // Completely okay, the whole Holder object is read
70      *     val jsonObject = JsonObject(...) // build a JsonObject from Holder
71      *     (encoder as JsonEncoder).encodeJsonElement(jsonObject) // Write it
72      * }
73      *
74      * // Incorrect Holder serialize method
75      * fun serialize(encoder: Encoder, value: Holder) {
76      *     val composite = encoder.beginStructure(descriptor)
77      *     composite.encodeSerializableElement(descriptor, 0, Int.serializer(), value.value)
78      *     val array = JsonArray(value.list)
79      *     // Incorrect, encoder is already in an intermediate state after encodeSerializableElement
80      *     (composite as JsonEncoder).encodeJsonElement(array)
81      *     composite.endStructure(descriptor)
82      *     // ...
83      * }
84      * ```
85      */
encodeJsonElementnull86     public fun encodeJsonElement(element: JsonElement)
87 }
88