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 6 7 import kotlinx.serialization.descriptors.* 8 import kotlinx.serialization.encoding.* 9 10 /** 11 * KSerializer is responsible for the representation of a serial form of a type [T] 12 * in terms of [encoders][Encoder] and [decoders][Decoder] and for constructing and deconstructing [T] 13 * from/to a sequence of encoding primitives. For classes marked with [@Serializable][Serializable], can be 14 * obtained from generated companion extension `.serializer()` or from [serializer<T>()][serializer] function. 15 * 16 * Serialization is decoupled from the encoding process to make it completely format-agnostic. 17 * Serialization represents a type as its serial form and is abstracted from the actual 18 * format (whether its JSON, ProtoBuf or a hashing) and unaware of the underlying storage 19 * (whether it is a string builder, byte array or a network socket), while 20 * encoding/decoding is abstracted from a particular type and its serial form and is responsible 21 * for transforming primitives ("here in an int property 'foo'" call from a serializer) into a particular 22 * format-specific representation ("for a given int, append a property name in quotation marks, 23 * then append a colon, then append an actual value" for JSON) and how to retrieve a primitive 24 * ("give me an int that is 'foo' property") from the underlying representation ("expect the next string to be 'foo', 25 * parse it, then parse colon, then parse a string until the next comma as an int and return it). 26 * 27 * Serial form consists of a structural description, declared by the [descriptor] and 28 * actual serialization and deserialization processes, defined by the corresponding 29 * [serialize] and [deserialize] methods implementation. 30 * 31 * Structural description specifies how the [T] is represented in the serial form: 32 * its [kind][SerialKind] (e.g. whether it is represented as a primitive, a list or a class), 33 * its [elements][SerialDescriptor.elementNames] and their [positional names][SerialDescriptor.getElementName]. 34 * 35 * Serialization process is defined as a sequence of calls to an [Encoder], and transforms a type [T] 36 * into a stream of format-agnostic primitives that represent [T], such as "here is an int, here is a double 37 * and here is another nested object". It can be demonstrated by the example: 38 * ``` 39 * class MyData(int: Int, stringList: List<String>, alwaysZero: Long) 40 * 41 * // .. serialize method of a corresponding serializer 42 * fun serialize(encoder: Encoder, value: MyData): Unit = encoder.encodeStructure(descriptor) { 43 * // encodeStructure encodes beginning and end of the structure 44 * // encode 'int' property as Int 45 * encodeIntElement(descriptor, index = 0, value.int) 46 * // encode 'stringList' property as List<String> 47 * encodeSerializableElement(descriptor, index = 1, serializer<List<String>>, value.stringList) 48 * // don't encode 'alwaysZero' property because we decided to do so 49 * } // end of the structure 50 * ``` 51 * 52 * Deserialization process is symmetric and uses [Decoder]. 53 * 54 * ### Exception types for `KSerializer` implementation 55 * 56 * Implementations of [serialize] and [deserialize] methods are allowed to throw 57 * any subtype of [IllegalArgumentException] in order to indicate serialization 58 * and deserialization errors. 59 * 60 * For serializer implementations, it is recommended to throw subclasses of [SerializationException] for 61 * any serialization-specific errors related to invalid or unsupported format of the data 62 * and [IllegalStateException] for errors during validation of the data. 63 */ 64 public interface KSerializer<T> : SerializationStrategy<T>, DeserializationStrategy<T> { 65 /** 66 * Describes the structure of the serializable representation of [T], produced 67 * by this serializer. Knowing the structure of the descriptor is required to determine 68 * the shape of the serialized form (e.g. what elements are encoded as lists and what as primitives) 69 * along with its metadata such as alternative names. 70 * 71 * The descriptor is used during serialization by encoders and decoders 72 * to introspect the type and metadata of [T]'s elements being encoded or decoded, and 73 * to introspect the type, infer the schema or to compare against the predefined schema. 74 */ 75 override val descriptor: SerialDescriptor 76 } 77 78 /** 79 * Serialization strategy defines the serial form of a type [T], including its structural description, 80 * declared by the [descriptor] and the actual serialization process, defined by the implementation 81 * of the [serialize] method. 82 * 83 * [serialize] method takes an instance of [T] and transforms it into its serial form (a sequence of primitives), 84 * calling the corresponding [Encoder] methods. 85 * 86 * A serial form of the type is a transformation of the concrete instance into a sequence of primitive values 87 * and vice versa. The serial form is not required to completely mimic the structure of the class, for example, 88 * a specific implementation may represent multiple integer values as a single string, omit or add some 89 * values that are present in the type, but not in the instance. 90 * 91 * For a more detailed explanation of the serialization process, please refer to [KSerializer] documentation. 92 */ 93 public interface SerializationStrategy<in T> { 94 /** 95 * Describes the structure of the serializable representation of [T], produced 96 * by this serializer. 97 */ 98 public val descriptor: SerialDescriptor 99 100 /** 101 * Serializes the [value] of type [T] using the format that is represented by the given [encoder]. 102 * [serialize] method is format-agnostic and operates with a high-level structured [Encoder] API. 103 * Throws [SerializationException] if value cannot be serialized. 104 * 105 * Example of serialize method: 106 * ``` 107 * class MyData(int: Int, stringList: List<String>, alwaysZero: Long) 108 * 109 * fun serialize(encoder: Encoder, value: MyData): Unit = encoder.encodeStructure(descriptor) { 110 * // encodeStructure encodes beginning and end of the structure 111 * // encode 'int' property as Int 112 * encodeIntElement(descriptor, index = 0, value.int) 113 * // encode 'stringList' property as List<String> 114 * encodeSerializableElement(descriptor, index = 1, serializer<List<String>>, value.stringList) 115 * // don't encode 'alwaysZero' property because we decided to do so 116 * } // end of the structure 117 * ``` 118 * 119 * @throws SerializationException in case of any serialization-specific error 120 * @throws IllegalArgumentException if the supplied input does not comply encoder's specification 121 * @see KSerializer for additional information about general contracts and exception specifics 122 */ serializenull123 public fun serialize(encoder: Encoder, value: T) 124 } 125 126 /** 127 * Deserialization strategy defines the serial form of a type [T], including its structural description, 128 * declared by the [descriptor] and the actual deserialization process, defined by the implementation 129 * of the [deserialize] method. 130 * 131 * [deserialize] method takes an instance of [Decoder], and, knowing the serial form of the [T], 132 * invokes primitive retrieval methods on the decoder and then transforms the received primitives 133 * to an instance of [T]. 134 * 135 * A serial form of the type is a transformation of the concrete instance into a sequence of primitive values 136 * and vice versa. The serial form is not required to completely mimic the structure of the class, for example, 137 * a specific implementation may represent multiple integer values as a single string, omit or add some 138 * values that are present in the type, but not in the instance. 139 * 140 * For a more detailed explanation of the serialization process, please refer to [KSerializer] documentation. 141 */ 142 public interface DeserializationStrategy<out T> { 143 /** 144 * Describes the structure of the serializable representation of [T], that current 145 * deserializer is able to deserialize. 146 */ 147 public val descriptor: SerialDescriptor 148 149 /** 150 * Deserializes the value of type [T] using the format that is represented by the given [decoder]. 151 * [deserialize] method is format-agnostic and operates with a high-level structured [Decoder] API. 152 * As long as most of the formats imply an arbitrary order of properties, deserializer should be able 153 * to decode these properties in an arbitrary order and in a format-agnostic way. 154 * For that purposes, [CompositeDecoder.decodeElementIndex]-based loop is used: decoder firstly 155 * signals property at which index it is ready to decode and then expects caller to decode 156 * property with the given index. 157 * 158 * Throws [SerializationException] if value cannot be deserialized. 159 * 160 * Example of deserialize method: 161 * ``` 162 * class MyData(int: Int, stringList: List<String>, alwaysZero: Long) 163 * 164 * fun deserialize(decoder: Decoder): MyData = decoder.decodeStructure(descriptor) { 165 * // decodeStructure decodes beginning and end of the structure 166 * var int: Int? = null 167 * var list: List<String>? = null 168 * loop@ while (true) { 169 * when (val index = decodeElementIndex(descriptor)) { 170 * DECODE_DONE -> break@loop 171 * 0 -> { 172 * // Decode 'int' property as Int 173 * int = decodeIntElement(descriptor, index = 0) 174 * } 175 * 1 -> { 176 * // Decode 'stringList' property as List<String> 177 * list = decodeSerializableElement(descriptor, index = 1, serializer<List<String>>()) 178 * } 179 * else -> throw SerializationException("Unexpected index $index") 180 * } 181 * } 182 * if (int == null || list == null) throwMissingFieldException() 183 * // Always use 0 as a value for alwaysZero property because we decided to do so. 184 * return MyData(int, list, alwaysZero = 0L) 185 * } 186 * ``` 187 * 188 * @throws MissingFieldException if non-optional fields were not found during deserialization 189 * @throws SerializationException in case of any deserialization-specific error 190 * @throws IllegalArgumentException if the decoded input is not a valid instance of [T] 191 * @see KSerializer for additional information about general contracts and exception specifics 192 */ 193 public fun deserialize(decoder: Decoder): T 194 } 195