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

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(this.kotlin.notRegisteredMessage())
}

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

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 = invokeSerializerOnDefaultCompanion(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 = findInNamedCompanion(*args)
    if (fromNamedCompanion != null) return fromNamedCompanion
    // Check for polymorphic
    return if (isPolymorphicSerializer()) {
        PolymorphicSerializer(this.kotlin)
    } else {
        null
    }
}

@Suppress("UNCHECKED_CAST")
private fun  Class.findInNamedCompanion(vararg args: KSerializer): KSerializer? {
    val namedCompanion = findNamedCompanionByAnnotation()
    if (namedCompanion != null) {
        invokeSerializerOnCompanion(namedCompanion, *args)?.let { return it }
    }

    // fallback strategy for old compiler - try to locate plugin-generated singleton (without type parameters) serializer
    return try {
        declaredClasses.singleOrNull { it.simpleName == ("\$serializer") }
            ?.getField("INSTANCE")?.get(null) as? KSerializer
    } catch (e: NoSuchFieldException) {
        null
    }
}

private fun  Class.findNamedCompanionByAnnotation(): Any? {
    val companionClass = declaredClasses.firstOrNull { clazz ->
        clazz.getAnnotation(NamedCompanion::class.java) != null
    } ?: return null

    return companionOrNull(companionClass.simpleName)
}

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
}

private fun  invokeSerializerOnDefaultCompanion(jClass: Class<*>, vararg args: KSerializer): KSerializer? {
    val companion = jClass.companionOrNull("Companion") ?: return null
    return invokeSerializerOnCompanion(companion, *args)
}

@Suppress("UNCHECKED_CAST")
private fun  invokeSerializerOnCompanion(companion: Any, vararg args: KSerializer): KSerializer? {
    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(companionName: String) =
    try {
        val companion = getDeclaredField(companionName)
        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? {
    // Special case to avoid IllegalAccessException on Java11+ (#2449)
    // There are no serializable objects in the stdlib anyway.
    if (this.canonicalName?.let { it.startsWith("java.") || it.startsWith("kotlin.") } != false) return null
    // 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
}

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




© 2015 - 2025 Weber Informatics LLC | Privacy Policy