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