1 /* 2 * Copyright 2017-2021 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 import kotlinx.serialization.internal.* 10 import kotlinx.serialization.modules.* 11 import kotlin.reflect.* 12 13 /** 14 * This class provides support for retrieving a serializer in runtime, instead of using the one precompiled by the serialization plugin. 15 * This serializer is enabled by [Contextual] or [UseContextualSerialization]. 16 * 17 * Typical usage of `ContextualSerializer` would be a serialization of a class which does not have 18 * static serializer (e.g. Java class or class from 3rd party library); 19 * or desire to override serialized class form in one dedicated output format. 20 * 21 * Serializers are being looked for in a [SerializersModule] from the target [Encoder] or [Decoder], using statically known [KClass]. 22 * To create a serial module, use [SerializersModule] factory function. 23 * To pass it to encoder and decoder, refer to particular [SerialFormat]'s documentation. 24 * 25 * Usage of contextual serializer can be demonstrated by the following example: 26 * ``` 27 * import java.util.Date 28 * 29 * @Serializable 30 * class ClassWithDate(val data: String, @Contextual val timestamp: Date) 31 * 32 * val moduleForDate = serializersModuleOf(MyISO8601DateSerializer) 33 * val json = Json { serializersModule = moduleForDate } 34 * json.encodeToString(ClassWithDate("foo", Date()) 35 * ``` 36 * 37 * If type of the property marked with `@Contextual` is `@Serializable` by itself, the plugin-generated serializer is 38 * used as a fallback if no serializers associated with a given type is registered in the module. 39 * The fallback serializer is determined by the static type of the property, not by its actual type. 40 */ 41 @ExperimentalSerializationApi 42 public class ContextualSerializer<T : Any>( 43 private val serializableClass: KClass<T>, 44 private val fallbackSerializer: KSerializer<T>?, 45 typeArgumentsSerializers: Array<KSerializer<*>> 46 ) : KSerializer<T> { 47 48 private val typeArgumentsSerializers: List<KSerializer<*>> = typeArgumentsSerializers.asList() 49 serializernull50 private fun serializer(serializersModule: SerializersModule): KSerializer<T> = 51 serializersModule.getContextual(serializableClass, typeArgumentsSerializers) ?: fallbackSerializer ?: serializableClass.serializerNotRegistered() 52 53 // Used from the old plugins 54 @Suppress("unused") 55 public constructor(serializableClass: KClass<T>) : this(serializableClass, null, EMPTY_SERIALIZER_ARRAY) 56 57 public override val descriptor: SerialDescriptor = 58 buildSerialDescriptor("kotlinx.serialization.ContextualSerializer", SerialKind.CONTEXTUAL) { 59 annotations = fallbackSerializer?.descriptor?.annotations.orEmpty() 60 }.withContext(serializableClass) 61 serializenull62 public override fun serialize(encoder: Encoder, value: T) { 63 encoder.encodeSerializableValue(serializer(encoder.serializersModule), value) 64 } 65 deserializenull66 public override fun deserialize(decoder: Decoder): T { 67 return decoder.decodeSerializableValue(serializer(decoder.serializersModule)) 68 } 69 } 70