fix: type erasure breaking nested generics (#285)

This commit is contained in:
Ryan Brink
2022-08-13 11:15:49 -07:00
committed by GitHub
parent 2e29b46f0f
commit 5beeade430
7 changed files with 302 additions and 10 deletions

View File

@ -13,6 +13,7 @@ import kotlin.reflect.KProperty
import kotlin.reflect.KType
import kotlin.reflect.KTypeParameter
import kotlin.reflect.KTypeProjection
import kotlin.reflect.full.createType
import kotlin.reflect.full.memberProperties
import kotlin.reflect.full.primaryConstructor
@ -22,9 +23,12 @@ object SimpleObjectHandler {
// cache[type.getSimpleSlug()] = ReferenceDefinition("RECURSION_PLACEHOLDER")
val typeMap = clazz.typeParameters.zip(type.arguments).toMap()
val props = clazz.memberProperties.associate { prop ->
val schema = when (typeMap.containsKey(prop.returnType.classifier)) {
true -> handleGenericProperty(prop, typeMap, cache)
false -> handleProperty(prop, cache)
val schema = when (prop.needsToInjectGenerics(typeMap)) {
true -> handleNestedGenerics(typeMap, prop, cache)
false -> when (typeMap.containsKey(prop.returnType.classifier)) {
true -> handleGenericProperty(prop, typeMap, cache)
false -> handleProperty(prop, cache)
}
}
prop.name to schema
@ -48,6 +52,34 @@ object SimpleObjectHandler {
}
}
private fun KProperty<*>.needsToInjectGenerics(
typeMap: Map<KTypeParameter, KTypeProjection>
): Boolean {
val typeSymbols = returnType.arguments.map { it.type.toString() }
return typeMap.any { (k, _) -> typeSymbols.contains(k.name) }
}
private fun handleNestedGenerics(
typeMap: Map<KTypeParameter, KTypeProjection>,
prop: KProperty<*>,
cache: MutableMap<String, JsonSchema>
): JsonSchema {
val propClass = prop.returnType.classifier as KClass<*>
val types = prop.returnType.arguments.map {
val typeSymbol = it.type.toString()
typeMap.filterKeys { k -> k.name == typeSymbol }.values.first()
}
val constructedType = propClass.createType(types)
return SchemaGenerator.fromTypeToSchema(constructedType, cache).let {
if (it is TypeDefinition && it.type == "object") {
cache[constructedType.getSimpleSlug()] = it
ReferenceDefinition(prop.returnType.getReferenceSlug())
} else {
it
}
}
}
private fun handleGenericProperty(
prop: KProperty<*>,
typeMap: Map<KTypeParameter, KTypeProjection>,