jvmMain.internal.KClass.kt Maven / Gradle / Ivy
package io.kform.internal
import kotlin.reflect.KClass
import kotlin.reflect.KMutableProperty1
import kotlin.reflect.KVisibility
internal actual fun constructFromKClass(
kClass: KClass,
childValues: Map,
childProps: Map>
): T {
// HACK: We try to find a "callable" constructor by matching property names with argument names;
// this is obviously **very** error-prone but will work nicely for the typical case where data
// classes are used
val minConstructor =
kClass.constructors
// Find all callable constructors (where params are either optional or their names match
// child prop names)
.filter { constructor ->
constructor.visibility != KVisibility.PRIVATE &&
constructor.parameters.all { param ->
param.name in childValues || param.isOptional
}
}
// Pick the constructor that takes the minimum amount of child properties
.minByOrNull { constructor -> constructor.parameters.size }
?: error(
"Could not find a callable constructor for '${kClass::qualifiedName}'. " +
"Please provide a [constructorFunction] when creating the schema."
)
// Create an instance of the class and keep track of which props were used to construct it
val usedProps = HashSet(childValues.size)
val instance =
minConstructor.call(
*minConstructor.parameters
.map { param ->
if (param.name in childValues) {
usedProps += param.name!!
childValues[param.name]
} else null
}
.toTypedArray()
)
// Manually set props that weren't used in the construction of the instance
if (usedProps.size < childValues.size) {
for ((name, value) in childValues) {
if (name !in usedProps) {
childProps[name]!!.set(instance, value)
}
}
}
return instance
}