1 /*
2 * Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3 */
4 @file:JvmMultifileClass
5 @file:JvmName("SerializersKt")
6 @file:Suppress("UNCHECKED_CAST")
7
8 package kotlinx.serialization
9
10 import kotlinx.serialization.builtins.*
11 import kotlinx.serialization.builtins.MapEntrySerializer
12 import kotlinx.serialization.builtins.PairSerializer
13 import kotlinx.serialization.builtins.TripleSerializer
14 import kotlinx.serialization.internal.*
15 import kotlinx.serialization.modules.*
16 import java.lang.reflect.*
17 import kotlin.reflect.*
18
19 /**
20 * Reflectively retrieves a serializer for the given [type].
21 *
22 * This overload is intended to be used as an interoperability layer for JVM-centric libraries,
23 * that operate with Java's type tokens and cannot use Kotlin's [KType] or [typeOf].
24 * For application-level serialization, it is recommended to use `serializer<T>()` or `serializer(KType)` instead as it is aware of
25 * Kotlin-specific type information, such as nullability, sealed classes and object singletons.
26 *
27 * Note that because [Type] does not contain any information about nullability, all created serializers
28 * work only with non-nullable data.
29 *
30 * Not all [Type] implementations are supported.
31 * [type] must be an instance of [Class], [GenericArrayType], [ParameterizedType] or [WildcardType].
32 *
33 * @throws SerializationException if serializer cannot be created (provided [type] or its type argument is not serializable).
34 * @throws IllegalArgumentException if an unsupported subclass of [Type] is provided.
35 */
serializernull36 public fun serializer(type: Type): KSerializer<Any> = EmptySerializersModule().serializer(type)
37
38 /**
39 * Reflectively retrieves a serializer for the given [type].
40 *
41 * This overload is intended to be used as an interoperability layer for JVM-centric libraries,
42 * that operate with Java's type tokens and cannot use Kotlin's [KType] or [typeOf].
43 * For application-level serialization, it is recommended to use `serializer<T>()` or `serializer(KType)` instead as it is aware of
44 * Kotlin-specific type information, such as nullability, sealed classes and object singletons.
45 *
46 * Note that because [Type] does not contain any information about nullability, all created serializers
47 * work only with non-nullable data.
48 *
49 * Not all [Type] implementations are supported.
50 * [type] must be an instance of [Class], [GenericArrayType], [ParameterizedType] or [WildcardType].
51 *
52 * @return [KSerializer] for given [type] or `null` if serializer cannot be created (given [type] or its type argument is not serializable).
53 * @throws IllegalArgumentException if an unsupported subclass of [Type] is provided.
54 */
55 public fun serializerOrNull(type: Type): KSerializer<Any>? = EmptySerializersModule().serializerOrNull(type)
56
57 /**
58 * Retrieves a serializer for the given [type] using
59 * reflective construction and [contextual][SerializersModule.getContextual] lookup as a fallback for non-serializable types.
60 *
61 * This overload is intended to be used as an interoperability layer for JVM-centric libraries,
62 * that operate with Java's type tokens and cannot use Kotlin's [KType] or [typeOf].
63 * For application-level serialization, it is recommended to use `serializer<T>()` or `serializer(KType)` instead as it is aware of
64 * Kotlin-specific type information, such as nullability, sealed classes and object singletons.
65 *
66 * Note that because [Type] does not contain any information about nullability, all created serializers
67 * work only with non-nullable data.
68 *
69 * Not all [Type] implementations are supported.
70 * [type] must be an instance of [Class], [GenericArrayType], [ParameterizedType] or [WildcardType].
71 *
72 * @throws SerializationException if serializer cannot be created (provided [type] or its type argument is not serializable).
73 * @throws IllegalArgumentException if an unsupported subclass of [Type] is provided.
74 */
75 public fun SerializersModule.serializer(type: Type): KSerializer<Any> =
76 serializerByJavaTypeImpl(type, failOnMissingTypeArgSerializer = true)
77 ?: type.prettyClass().serializerNotRegistered()
78
79 /**
80 * Retrieves a serializer for the given [type] using
81 * reflective construction and [contextual][SerializersModule.getContextual] lookup as a fallback for non-serializable types.
82 *
83 * This overload is intended to be used as an interoperability layer for JVM-centric libraries,
84 * that operate with Java's type tokens and cannot use Kotlin's [KType] or [typeOf].
85 * For application-level serialization, it is recommended to use `serializer<T>()` or `serializer(KType)` instead as it is aware of
86 * Kotlin-specific type information, such as nullability, sealed classes and object singletons.
87 *
88 * Note that because [Type] does not contain any information about nullability, all created serializers
89 * work only with non-nullable data.
90 *
91 * Not all [Type] implementations are supported.
92 * [type] must be an instance of [Class], [GenericArrayType], [ParameterizedType] or [WildcardType].
93 *
94 * @return [KSerializer] for given [type] or `null` if serializer cannot be created (given [type] or its type argument is not serializable).
95 * @throws IllegalArgumentException if an unsupported subclass of [Type] is provided.
96 */
97 public fun SerializersModule.serializerOrNull(type: Type): KSerializer<Any>? =
98 serializerByJavaTypeImpl(type, failOnMissingTypeArgSerializer = false)
99
100 private fun SerializersModule.serializerByJavaTypeImpl(
101 type: Type,
102 failOnMissingTypeArgSerializer: Boolean = true
103 ): KSerializer<Any>? =
104 when (type) {
105 is GenericArrayType -> {
106 genericArraySerializer(type, failOnMissingTypeArgSerializer)
107 }
108 is Class<*> -> typeSerializer(type, failOnMissingTypeArgSerializer)
109 is ParameterizedType -> {
110 val rootClass = (type.rawType as Class<*>)
111 val args = (type.actualTypeArguments)
112 val argsSerializers =
113 if (failOnMissingTypeArgSerializer) args.map { serializer(it) } else args.map {
114 serializerOrNull(it) ?: return null
115 }
116 when {
117 Set::class.java.isAssignableFrom(rootClass) -> SetSerializer(argsSerializers[0]) as KSerializer<Any>
118 List::class.java.isAssignableFrom(rootClass) || Collection::class.java.isAssignableFrom(rootClass) -> ListSerializer(
119 argsSerializers[0]
120 ) as KSerializer<Any>
121 Map::class.java.isAssignableFrom(rootClass) -> MapSerializer(
122 argsSerializers[0],
123 argsSerializers[1]
124 ) as KSerializer<Any>
125 Map.Entry::class.java.isAssignableFrom(rootClass) -> MapEntrySerializer(
126 argsSerializers[0],
127 argsSerializers[1]
128 ) as KSerializer<Any>
129 Pair::class.java.isAssignableFrom(rootClass) -> PairSerializer(
130 argsSerializers[0],
131 argsSerializers[1]
132 ) as KSerializer<Any>
133 Triple::class.java.isAssignableFrom(rootClass) -> TripleSerializer(
134 argsSerializers[0],
135 argsSerializers[1],
136 argsSerializers[2]
137 ) as KSerializer<Any>
138
139 else -> {
140 val varargs = argsSerializers.map { it as KSerializer<Any?> }
141 reflectiveOrContextual(rootClass as Class<Any>, varargs)
142 }
143 }
144 }
145 is WildcardType -> serializerByJavaTypeImpl(type.upperBounds.first())
146 else -> throw IllegalArgumentException("type should be an instance of Class<?>, GenericArrayType, ParametrizedType or WildcardType, but actual argument $type has type ${type::class}")
147 }
148
149 @OptIn(ExperimentalSerializationApi::class)
typeSerializernull150 private fun SerializersModule.typeSerializer(
151 type: Class<*>,
152 failOnMissingTypeArgSerializer: Boolean
153 ): KSerializer<Any>? {
154 return if (type.isArray && !type.componentType.isPrimitive) {
155 val eType: Class<*> = type.componentType
156 val s = if (failOnMissingTypeArgSerializer) serializer(eType) else (serializerOrNull(eType) ?: return null)
157 val arraySerializer = ArraySerializer(eType.kotlin as KClass<Any>, s)
158 arraySerializer as KSerializer<Any>
159 } else {
160 reflectiveOrContextual(type as Class<Any>, emptyList())
161 }
162 }
163
164 @OptIn(ExperimentalSerializationApi::class)
reflectiveOrContextualnull165 private fun <T : Any> SerializersModule.reflectiveOrContextual(
166 jClass: Class<T>,
167 typeArgumentsSerializers: List<KSerializer<Any?>>
168 ): KSerializer<T>? {
169 jClass.constructSerializerForGivenTypeArgs(*typeArgumentsSerializers.toTypedArray())?.let { return it }
170 val kClass = jClass.kotlin
171 return kClass.builtinSerializerOrNull() ?: getContextual(kClass, typeArgumentsSerializers)
172 }
173
174 @OptIn(ExperimentalSerializationApi::class)
genericArraySerializernull175 private fun SerializersModule.genericArraySerializer(
176 type: GenericArrayType,
177 failOnMissingTypeArgSerializer: Boolean
178 ): KSerializer<Any>? {
179 val eType = type.genericComponentType.let {
180 when (it) {
181 is WildcardType -> it.upperBounds.first()
182 else -> it
183 }
184 }
185 val serializer = if (failOnMissingTypeArgSerializer) serializer(eType) else (serializerOrNull(eType) ?: return null)
186 val kclass = when (eType) {
187 is ParameterizedType -> (eType.rawType as Class<*>).kotlin
188 is KClass<*> -> eType
189 else -> throw IllegalStateException("unsupported type in GenericArray: ${eType::class}")
190 } as KClass<Any>
191 return ArraySerializer(kclass, serializer) as KSerializer<Any>
192 }
193
Typenull194 private fun Type.prettyClass(): Class<*> = when (val it = this) {
195 is Class<*> -> it
196 is ParameterizedType -> it.rawType.prettyClass()
197 is WildcardType -> it.upperBounds.first().prettyClass()
198 is GenericArrayType -> it.genericComponentType.prettyClass()
199 else -> throw IllegalArgumentException("type should be an instance of Class<?>, GenericArrayType, ParametrizedType or WildcardType, but actual argument $it has type ${it::class}")
200 }
201