
jvmMain.kotlinx.serialization.SerializersJvm.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kotlinx-serialization-core-jvm Show documentation
Show all versions of kotlinx-serialization-core-jvm Show documentation
Kotlin multiplatform serialization runtime library
/*
* Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:JvmMultifileClass
@file:JvmName("SerializersKt")
@file:Suppress("UNCHECKED_CAST")
package kotlinx.serialization
import kotlinx.serialization.builtins.*
import kotlinx.serialization.builtins.MapEntrySerializer
import kotlinx.serialization.builtins.PairSerializer
import kotlinx.serialization.builtins.TripleSerializer
import kotlinx.serialization.internal.*
import kotlinx.serialization.modules.*
import java.lang.reflect.*
import kotlin.reflect.*
/**
* Reflectively retrieves a serializer for the given [type].
*
* This overload is intended to be used as an interoperability layer for JVM-centric libraries,
* that operate with Java's type tokens and cannot use Kotlin's [KType] or [typeOf].
* For application-level serialization, it is recommended to use `serializer()` or `serializer(KType)` instead as it is aware of
* Kotlin-specific type information, such as nullability, sealed classes and object singletons.
*
* Note that because [Type] does not contain any information about nullability, all created serializers
* work only with non-nullable data.
*
* Not all [Type] implementations are supported.
* [type] must be an instance of [Class], [GenericArrayType], [ParameterizedType] or [WildcardType].
*
* @throws SerializationException if serializer cannot be created (provided [type] or its type argument is not serializable).
* @throws IllegalArgumentException if an unsupported subclass of [Type] is provided.
*/
public fun serializer(type: Type): KSerializer = EmptySerializersModule().serializer(type)
/**
* Reflectively retrieves a serializer for the given [type].
*
* This overload is intended to be used as an interoperability layer for JVM-centric libraries,
* that operate with Java's type tokens and cannot use Kotlin's [KType] or [typeOf].
* For application-level serialization, it is recommended to use `serializer()` or `serializer(KType)` instead as it is aware of
* Kotlin-specific type information, such as nullability, sealed classes and object singletons.
*
* Note that because [Type] does not contain any information about nullability, all created serializers
* work only with non-nullable data.
*
* Not all [Type] implementations are supported.
* [type] must be an instance of [Class], [GenericArrayType], [ParameterizedType] or [WildcardType].
*
* @return [KSerializer] for given [type] or `null` if serializer cannot be created (given [type] or its type argument is not serializable).
* @throws IllegalArgumentException if an unsupported subclass of [Type] is provided.
*/
public fun serializerOrNull(type: Type): KSerializer? = EmptySerializersModule().serializerOrNull(type)
/**
* Retrieves a serializer for the given [type] using
* reflective construction and [contextual][SerializersModule.getContextual] lookup as a fallback for non-serializable types.
*
* This overload is intended to be used as an interoperability layer for JVM-centric libraries,
* that operate with Java's type tokens and cannot use Kotlin's [KType] or [typeOf].
* For application-level serialization, it is recommended to use `serializer()` or `serializer(KType)` instead as it is aware of
* Kotlin-specific type information, such as nullability, sealed classes and object singletons.
*
* Note that because [Type] does not contain any information about nullability, all created serializers
* work only with non-nullable data.
*
* Not all [Type] implementations are supported.
* [type] must be an instance of [Class], [GenericArrayType], [ParameterizedType] or [WildcardType].
*
* @throws SerializationException if serializer cannot be created (provided [type] or its type argument is not serializable).
* @throws IllegalArgumentException if an unsupported subclass of [Type] is provided.
*/
public fun SerializersModule.serializer(type: Type): KSerializer =
serializerByJavaTypeImpl(type, failOnMissingTypeArgSerializer = true)
?: type.prettyClass().serializerNotRegistered()
/**
* Retrieves a serializer for the given [type] using
* reflective construction and [contextual][SerializersModule.getContextual] lookup as a fallback for non-serializable types.
*
* This overload is intended to be used as an interoperability layer for JVM-centric libraries,
* that operate with Java's type tokens and cannot use Kotlin's [KType] or [typeOf].
* For application-level serialization, it is recommended to use `serializer()` or `serializer(KType)` instead as it is aware of
* Kotlin-specific type information, such as nullability, sealed classes and object singletons.
*
* Note that because [Type] does not contain any information about nullability, all created serializers
* work only with non-nullable data.
*
* Not all [Type] implementations are supported.
* [type] must be an instance of [Class], [GenericArrayType], [ParameterizedType] or [WildcardType].
*
* @return [KSerializer] for given [type] or `null` if serializer cannot be created (given [type] or its type argument is not serializable).
* @throws IllegalArgumentException if an unsupported subclass of [Type] is provided.
*/
public fun SerializersModule.serializerOrNull(type: Type): KSerializer? =
serializerByJavaTypeImpl(type, failOnMissingTypeArgSerializer = false)
private fun SerializersModule.serializerByJavaTypeImpl(
type: Type,
failOnMissingTypeArgSerializer: Boolean = true
): KSerializer? =
when (type) {
is GenericArrayType -> {
genericArraySerializer(type, failOnMissingTypeArgSerializer)
}
is Class<*> -> typeSerializer(type, failOnMissingTypeArgSerializer)
is ParameterizedType -> {
val rootClass = (type.rawType as Class<*>)
val args = (type.actualTypeArguments)
val argsSerializers =
if (failOnMissingTypeArgSerializer) args.map { serializer(it) } else args.map {
serializerOrNull(it) ?: return null
}
when {
Set::class.java.isAssignableFrom(rootClass) -> SetSerializer(argsSerializers[0]) as KSerializer
List::class.java.isAssignableFrom(rootClass) || Collection::class.java.isAssignableFrom(rootClass) -> ListSerializer(
argsSerializers[0]
) as KSerializer
Map::class.java.isAssignableFrom(rootClass) -> MapSerializer(
argsSerializers[0],
argsSerializers[1]
) as KSerializer
Map.Entry::class.java.isAssignableFrom(rootClass) -> MapEntrySerializer(
argsSerializers[0],
argsSerializers[1]
) as KSerializer
Pair::class.java.isAssignableFrom(rootClass) -> PairSerializer(
argsSerializers[0],
argsSerializers[1]
) as KSerializer
Triple::class.java.isAssignableFrom(rootClass) -> TripleSerializer(
argsSerializers[0],
argsSerializers[1],
argsSerializers[2]
) as KSerializer
else -> {
val varargs = argsSerializers.map { it as KSerializer }
reflectiveOrContextual(rootClass as Class, varargs)
}
}
}
is WildcardType -> serializerByJavaTypeImpl(type.upperBounds.first())
else -> throw IllegalArgumentException("type should be an instance of Class>, GenericArrayType, ParametrizedType or WildcardType, but actual argument $type has type ${type::class}")
}
@OptIn(ExperimentalSerializationApi::class)
private fun SerializersModule.typeSerializer(
type: Class<*>,
failOnMissingTypeArgSerializer: Boolean
): KSerializer? {
return if (type.isArray && !type.componentType.isPrimitive) {
val eType: Class<*> = type.componentType
val s = if (failOnMissingTypeArgSerializer) serializer(eType) else (serializerOrNull(eType) ?: return null)
val arraySerializer = ArraySerializer(eType.kotlin as KClass, s)
arraySerializer as KSerializer
} else {
reflectiveOrContextual(type as Class, emptyList())
}
}
@OptIn(ExperimentalSerializationApi::class)
private fun SerializersModule.reflectiveOrContextual(
jClass: Class,
typeArgumentsSerializers: List>
): KSerializer? {
jClass.constructSerializerForGivenTypeArgs(*typeArgumentsSerializers.toTypedArray())?.let { return it }
val kClass = jClass.kotlin
return kClass.builtinSerializerOrNull() ?: getContextual(kClass, typeArgumentsSerializers) ?: if (jClass.isInterface) PolymorphicSerializer(jClass.kotlin) else null
}
@OptIn(ExperimentalSerializationApi::class)
private fun SerializersModule.genericArraySerializer(
type: GenericArrayType,
failOnMissingTypeArgSerializer: Boolean
): KSerializer? {
val eType = type.genericComponentType.let {
when (it) {
is WildcardType -> it.upperBounds.first()
else -> it
}
}
val serializer = if (failOnMissingTypeArgSerializer) serializer(eType) else (serializerOrNull(eType) ?: return null)
val kclass = when (eType) {
is ParameterizedType -> (eType.rawType as Class<*>).kotlin
is KClass<*> -> eType
else -> throw IllegalStateException("unsupported type in GenericArray: ${eType::class}")
} as KClass
return ArraySerializer(kclass, serializer) as KSerializer
}
private fun Type.prettyClass(): Class<*> = when (val it = this) {
is Class<*> -> it
is ParameterizedType -> it.rawType.prettyClass()
is WildcardType -> it.upperBounds.first().prettyClass()
is GenericArrayType -> it.genericComponentType.prettyClass()
else -> throw IllegalArgumentException("type should be an instance of Class>, GenericArrayType, ParametrizedType or WildcardType, but actual argument $it has type ${it::class}")
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy