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

jvmMain.kotlinx.serialization.internal.Platform.kt Maven / Gradle / Ivy

/*
 * Copyright 2017-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
 */

package kotlinx.serialization.internal

import kotlinx.serialization.*
import java.lang.reflect.*
import kotlin.reflect.*

@Suppress("NOTHING_TO_INLINE")
internal actual inline fun  Array.getChecked(index: Int): T {
    return get(index)
}

@Suppress("NOTHING_TO_INLINE")
internal actual inline fun BooleanArray.getChecked(index: Int): Boolean {
    return get(index)
}

@Suppress("UNCHECKED_CAST")
internal actual fun  KClass.compiledSerializerImpl(): KSerializer? =
    this.constructSerializerForGivenTypeArgs()

@Suppress("UNCHECKED_CAST")
internal actual fun  ArrayList.toNativeArrayImpl(eClass: KClass): Array =
    toArray(java.lang.reflect.Array.newInstance(eClass.java, size) as Array)

internal actual fun KClass<*>.platformSpecificSerializerNotRegistered(): Nothing = serializerNotRegistered()

internal fun Class<*>.serializerNotRegistered(): Nothing {
    throw SerializationException(
        "Serializer for class '${simpleName}' is not found.\n" +
                "Mark the class as @Serializable or provide the serializer explicitly."
    )
}

internal actual fun  KClass.constructSerializerForGivenTypeArgs(vararg args: KSerializer): KSerializer? {
    return java.constructSerializerForGivenTypeArgs(*args)
}

@Suppress("UNCHECKED_CAST")
internal fun  Class.constructSerializerForGivenTypeArgs(vararg args: KSerializer): KSerializer? {
    if (isEnum && isNotAnnotated()) {
        return createEnumSerializer()
    }
    // Fall-through if the serializer is not found -- lookup on companions (for sealed interfaces) or fallback to polymorphic if applicable
    if (isInterface) interfaceSerializer()?.let { return it }
    // Search for serializer defined on companion object.
    val serializer = invokeSerializerOnCompanion(this, *args)
    if (serializer != null) return serializer
    // Check whether it's serializable object
    findObjectSerializer()?.let { return it }
    // Search for default serializer if no serializer is defined in companion object.
    // It is required for named companions
    val fromNamedCompanion = try {
        declaredClasses.singleOrNull { it.simpleName == ("\$serializer") }
            ?.getField("INSTANCE")?.get(null) as? KSerializer
    } catch (e: NoSuchFieldException) {
        null
    }
    if (fromNamedCompanion != null) return fromNamedCompanion
    // Check for polymorphic
    return if (isPolymorphicSerializer()) {
        PolymorphicSerializer(this.kotlin)
    } else {
        null
    }
}

private fun  Class.isNotAnnotated(): Boolean {
    /*
     * For annotated enums search serializer directly (or do not search at all?)
     */
    return getAnnotation(Serializable::class.java) == null &&
            getAnnotation(Polymorphic::class.java) == null
}

private fun  Class.isPolymorphicSerializer(): Boolean {
    /*
     * Last resort: check for @Polymorphic or Serializable(with = PolymorphicSerializer::class)
     * annotations.
     */
    if (getAnnotation(Polymorphic::class.java) != null) {
        return true
    }
    val serializable = getAnnotation(Serializable::class.java)
    if (serializable != null && serializable.with == PolymorphicSerializer::class) {
        return true
    }
    return false
}

private fun  Class.interfaceSerializer(): KSerializer? {
    /*
     * Interfaces are @Polymorphic by default.
     * Check if it has no annotations or `@Serializable(with = PolymorphicSerializer::class)`,
     * otherwise bailout.
     */
    val serializable = getAnnotation(Serializable::class.java)
    if (serializable == null || serializable.with == PolymorphicSerializer::class) {
        return PolymorphicSerializer(this.kotlin)
    }
    return null
}

@Suppress("UNCHECKED_CAST")
private fun  invokeSerializerOnCompanion(jClass: Class<*>, vararg args: KSerializer): KSerializer? {
    val companion = jClass.companionOrNull() ?: return null
    return try {
        val types = if (args.isEmpty()) emptyArray() else Array(args.size) { KSerializer::class.java }
        companion.javaClass.getDeclaredMethod("serializer", *types)
            .invoke(companion, *args) as? KSerializer
    } catch (e: NoSuchMethodException) {
        null
    } catch (e: InvocationTargetException) {
        val cause = e.cause ?: throw e
        throw InvocationTargetException(cause, cause.message ?: e.message)
    }
}

private fun Class<*>.companionOrNull() =
    try {
        val companion = getDeclaredField("Companion")
        companion.isAccessible = true
        companion.get(null)
    } catch (e: Throwable) {
        null
    }

@Suppress("UNCHECKED_CAST")
private fun  Class.createEnumSerializer(): KSerializer {
    val constants = enumConstants
    return EnumSerializer(canonicalName, constants as Array>) as KSerializer
}

private fun  Class.findObjectSerializer(): KSerializer? {
    // Check it is an object without using kotlin-reflect
    val field =
        declaredFields.singleOrNull { it.name == "INSTANCE" && it.type == this && Modifier.isStatic(it.modifiers) }
            ?: return null
    // Retrieve its instance and call serializer()
    val instance = field.get(null)
    val method =
        methods.singleOrNull { it.name == "serializer" && it.parameterTypes.isEmpty() && it.returnType == KSerializer::class.java }
            ?: return null
    val result = method.invoke(instance)
    @Suppress("UNCHECKED_CAST")
    return result as? KSerializer
}

/**
 * Checks if an [this@isInstanceOf] is an instance of a given [kclass].
 *
 * This check is a replacement for [KClass.isInstance] because
 * on JVM it requires kotlin-reflect.jar in classpath
 * (see https://youtrack.jetbrains.com/issue/KT-14720).
 *
 * On JS and Native, this function delegates to aforementioned
 * [KClass.isInstance] since it is supported there out-of-the box;
 * on JVM, it falls back to java.lang.Class.isInstance, which causes
 * difference when applied to function types with big arity.
 */
internal actual fun Any.isInstanceOf(kclass: KClass<*>): Boolean = kclass.javaObjectType.isInstance(this)

internal actual fun isReferenceArray(rootClass: KClass): Boolean = rootClass.java.isArray




© 2015 - 2025 Weber Informatics LLC | Privacy Policy