jvmMain.ch.softappeal.yass2.serialize.binary.BinarySerializerReflection.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of yass2-jvm Show documentation
Show all versions of yass2-jvm Show documentation
Yet Another Service Solution
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