All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jvmMain.kotlinx.serialization.SerializersJvm.kt Maven / Gradle / Ivy

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()
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy