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

jvmMain.ch.softappeal.yass2.serialize.binary.BinarySerializerReflection.kt Maven / Gradle / Ivy

There is a newer version: 5.0.0
Show newest version
package ch.softappeal.yass2.serialize.binary

import ch.softappeal.yass2.serialize.*
import kotlin.reflect.*
import kotlin.reflect.full.*

internal fun KClass<*>.mClass(baseEncoderTypes: List>, concreteClasses: List>): MClass {
    require(!java.isEnum) { "type '$this' is enum" }
    require(!isAbstract) { "type '$this' is abstract" }
    require(!isSubclassOf(Collection::class)) { "collection type '$this' is not allowed" }
    return MClass(
        this,
        memberProperties
            .filter { !isSubclassOf(Throwable::class) || (it.name != "cause" && it.name != "message") }
            .sortedBy { it.name }
            .map { property ->
                tailrec fun check(returnType: KType) {
                    val type = returnType.classifier as KClass<*>
                    if (type !in baseEncoderTypes) {
                        if (type == List::class)
                            check(returnType.arguments[0].type!!)
                        else if (type !in concreteClasses && !concreteClasses.any { it.isSubclassOf(type) })
                            error("property '${property.name}' of '$this' needs unknown type '$type'")
                    }
                }
                check(property.returnType)
                @Suppress("UNCHECKED_CAST") (property.returnType.classifier as KClass<*>).mProperty(
                    property as KProperty1, baseEncoderTypes, concreteClasses, property.returnType.isMarkedNullable
                ) { it != this && isSubclassOf(it) }
            },
        (primaryConstructor ?: error("'$this' has no primary constructor")).valueParameters.map { it.name!! }
    )
}

fun reflectionBinarySerializer(baseEncoders: List>, concreteClasses: List>): Serializer {
    val baseEncoderTypes = baseEncoders.map { it.type }
    val encoders = mutableListOf()
    encoders.addAll(baseEncoders)
    concreteClasses.forEach { klass ->
        val mClass = klass.mClass(baseEncoderTypes, concreteClasses)
        @Suppress("UNCHECKED_CAST") encoders.add(ClassEncoder(klass as KClass,
            { writer, instance -> mClass.properties.forEach { it.write(writer, it.property.get(instance)) } },
            { reader ->
                val properties = Array(mClass.properties.size) { mClass.properties[it].read(reader) }
                val instance = klass.primaryConstructor!!.call(*Array(mClass.parameterIndices.size) {
                    properties[mClass.parameterIndices[it]]
                })
                mClass.varIndices.forEach { mClass.properties[it].mutableProperty().set(instance, properties[it]) }
                instance
            }
        ))
    }
    return BinarySerializer(encoders)
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy