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-metadata Show documentation
Show all versions of kotlinx-serialization-core-metadata Show documentation
Kotlin multiplatform serialization runtime library
The newest version!
/*
* Copyright 2017-2020 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.*
/**
* Constructs a serializer for the given reflective Java [type].
* [serializer] is intended to be used as an interoperability layer for libraries like GSON and Retrofit,
* that operate with reflective Java [Type] and cannot use [typeOf].
*
* For application-level serialization, it is recommended to use `serializer()` instead as it is aware of
* Kotlin-specific type information, such as nullability, sealed classes and object.
*/
@ExperimentalSerializationApi
public fun serializer(type: Type): KSerializer = EmptySerializersModule.serializer(type)
/**
* Retrieves serializer for the given reflective Java [type] using
* reflective construction and [contextual][SerializersModule.getContextual] lookup for non-serializable types.
*
* [serializer] is intended to be used as an interoperability layer for libraries like GSON and Retrofit,
* that operate with reflective Java [Type] and cannot use [typeOf].
*
* For application-level serialization, it is recommended to use `serializer()` instead as it is aware of
* Kotlin-specific type information, such as nullability, sealed classes and object singletons.
*/
@ExperimentalSerializationApi
public fun SerializersModule.serializer(type: Type): KSerializer = when (type) {
is GenericArrayType -> {
genericArraySerializer(type)
}
is Class<*> -> typeSerializer(type)
is ParameterizedType -> {
val rootClass = (type.rawType as Class<*>)
val args = (type.actualTypeArguments)
when {
List::class.java.isAssignableFrom(rootClass) -> ListSerializer(serializer(args[0])) as KSerializer
Set::class.java.isAssignableFrom(rootClass) -> SetSerializer(serializer(args[0])) as KSerializer
Map::class.java.isAssignableFrom(rootClass) -> MapSerializer(
serializer(args[0]),
serializer(args[1])
) as KSerializer
Map.Entry::class.java.isAssignableFrom(rootClass) -> MapEntrySerializer(
serializer(args[0]),
serializer(args[1])
) as KSerializer
Pair::class.java.isAssignableFrom(rootClass) -> PairSerializer(
serializer(args[0]),
serializer(args[1])
) as KSerializer
Triple::class.java.isAssignableFrom(rootClass) -> TripleSerializer(
serializer(args[0]),
serializer(args[1]),
serializer(args[2])
) as KSerializer
else -> {
// probably we should deprecate this method because it can't differ nullable vs non-nullable types
// since it uses Java TypeToken, not Kotlin one
val varargs = args.map { serializer(it) as KSerializer }.toTypedArray()
(rootClass.kotlin.constructSerializerForGivenTypeArgs(*varargs) as? KSerializer)
?: reflectiveOrContextual(rootClass.kotlin as KClass)
}
}
}
is WildcardType -> serializer(type.upperBounds.first())
else -> throw IllegalArgumentException("typeToken should be an instance of Class>, GenericArray, ParametrizedType or WildcardType, but actual type is $type ${type::class}")
}
@OptIn(ExperimentalSerializationApi::class)
private fun SerializersModule.typeSerializer(type: Class<*>): KSerializer {
return if (!type.isArray) {
reflectiveOrContextual(type.kotlin as KClass)
} else {
val eType: Class<*> = type.componentType
val s = serializer(eType)
val arraySerializer = ArraySerializer(eType.kotlin as KClass, s)
arraySerializer as KSerializer
}
}
@OptIn(ExperimentalSerializationApi::class)
private fun SerializersModule.genericArraySerializer(type: GenericArrayType): KSerializer {
val eType = type.genericComponentType.let {
when (it) {
is WildcardType -> it.upperBounds.first()
else -> it
}
}
val serializer = serializer(eType)
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
}
@OptIn(ExperimentalSerializationApi::class)
private fun SerializersModule.reflectiveOrContextual(kClass: KClass): KSerializer {
return kClass.serializerOrNull() ?: getContextual(kClass) ?: kClass.serializerNotRegistered()
}