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