xref: /aosp_15_r20/external/kotlinx.serialization/core/jvmMain/src/kotlinx/serialization/SerializersJvm.kt (revision 57b5a4a64c534cf7f27ac9427ceab07f3d8ed3d8)
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