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 @file:Suppress("DeprecatedCallableAddReplaceWith")
6 
7 package kotlinx.serialization.json
8 
9 import kotlinx.serialization.*
10 import kotlinx.serialization.descriptors.*
11 import kotlinx.serialization.encoding.*
12 import kotlinx.serialization.json.internal.*
13 
14 /**
15  * Base class for custom serializers that allows manipulating an abstract JSON
16  * representation of the class before serialization or deserialization.
17  *
18  * [JsonTransformingSerializer] provides capabilities to manipulate [JsonElement] representation
19  * directly instead of interacting with [Encoder] and [Decoder] in order to apply a custom
20  * transformation to the JSON.
21  * Please note that this class expects that [Encoder] and [Decoder] are implemented by [JsonDecoder] and [JsonEncoder],
22  * i.e. serializers derived from this class work only with [Json] format.
23  *
24  * There are two methods in which JSON transformation can be defined: [transformSerialize] and [transformDeserialize].
25  * You can override one or both of them. Consult their documentation for details.
26  *
27  * Usage example:
28  *
29  * ```
30  * @Serializable
31  * data class Example(
32  *     @Serializable(UnwrappingJsonListSerializer::class) val data: String
33  * )
34  * // Unwraps a list to a single object
35  * object UnwrappingJsonListSerializer :
36  *     JsonTransformingSerializer<String>(String.serializer()) {
37  *     override fun transformDeserialize(element: JsonElement): JsonElement {
38  *         if (element !is JsonArray) return element
39  *         require(element.size == 1) { "Array size must be equal to 1 to unwrap it" }
40  *         return element.first()
41  *     }
42  * }
43  * // Now these functions both yield correct result:
44  * Json.parse(Example.serializer(), """{"data":["str1"]}""")
45  * Json.parse(Example.serializer(), """{"data":"str1"}""")
46  * ```
47  *
48  * @param T A type for Kotlin property for which this serializer could be applied.
49  *        **Not** the type that you may encounter in JSON. (e.g. if you unwrap a list
50  *        to a single value `T`, use `T`, not `List<T>`)
51  * @param tSerializer A serializer for type [T]. Determines [JsonElement] which is passed to [transformSerialize].
52  *        Should be able to parse [JsonElement] from [transformDeserialize] function.
53  *        Usually, default [serializer] is sufficient.
54  */
55 public abstract class JsonTransformingSerializer<T : Any>(
56     private val tSerializer: KSerializer<T>
57 ) : KSerializer<T> {
58 
59     /**
60      * A descriptor for this transformation.
61      * By default, it delegates to [tSerializer]'s descriptor.
62      *
63      * However, this descriptor can be overridden to achieve better representation of the resulting JSON shape
64      * for schema generating or introspection purposes.
65      */
66     override val descriptor: SerialDescriptor get() = tSerializer.descriptor
67 
serializenull68     final override fun serialize(encoder: Encoder, value: T) {
69         val output = encoder.asJsonEncoder()
70         var element = writeJson(output.json, value, tSerializer)
71         element = transformSerialize(element)
72         output.encodeJsonElement(element)
73     }
74 
deserializenull75     final override fun deserialize(decoder: Decoder): T {
76         val input = decoder.asJsonDecoder()
77         val element = input.decodeJsonElement()
78         return input.json.decodeFromJsonElement(tSerializer, transformDeserialize(element))
79     }
80 
81     /**
82      * Transformation that happens during [deserialize] call.
83      * Does nothing by default.
84      *
85      * During deserialization, a value from JSON is firstly decoded to a [JsonElement],
86      * user transformation in [transformDeserialize] is applied,
87      * and then resulting [JsonElement] is deserialized to [T] with [tSerializer].
88      */
transformDeserializenull89     protected open fun transformDeserialize(element: JsonElement): JsonElement = element
90 
91     /**
92      * Transformation that happens during [serialize] call.
93      * Does nothing by default.
94      *
95      * During serialization, a value of type [T] is serialized with [tSerializer] to a [JsonElement],
96      * user transformation in [transformSerialize] is applied, and then resulting [JsonElement] is encoded to a JSON string.
97      */
98     protected open fun transformSerialize(element: JsonElement): JsonElement = element
99 }
100