Skip to content

Commit 13b22ba

Browse files
committed
rebuilt validation system
added validators on min/max/clamp
1 parent b3eb5df commit 13b22ba

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+719
-374
lines changed

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
plugins {
2-
id "org.jetbrains.kotlin.jvm" version "1.3.61"
2+
id "org.jetbrains.kotlin.jvm" version "$kotlin_version"
33
}
44

55
group 'com.papsign.ktor'

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
kotlin.code.style=official
22
ktor_version=1.2.6
33
logback_version=1.2.1
4-
kotlin_version=1.3.61
4+
kotlin_version=1.3.70

src/main/kotlin/com/papsign/ktor/openapigen/KTypeUtil.kt

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
package com.papsign.ktor.openapigen
22

3-
import kotlin.reflect.KType
3+
import java.lang.reflect.Field
4+
import kotlin.reflect.*
45
import kotlin.reflect.full.createType
6+
import kotlin.reflect.full.declaredMemberProperties
7+
import kotlin.reflect.full.memberProperties
8+
import kotlin.reflect.jvm.javaField
59
import kotlin.reflect.jvm.jvmErasure
6-
import kotlin.reflect.typeOf
710

811
val unitKType = getKType<Unit>()
912

@@ -20,3 +23,24 @@ fun KType.strip(nullable: Boolean = isMarkedNullable): KType {
2023
fun KType.deepStrip(nullable: Boolean = isMarkedNullable): KType {
2124
return jvmErasure.createType(arguments.map { it.copy(type = it.type?.deepStrip()) }, nullable)
2225
}
26+
27+
data class KTypeProperty(
28+
val name: String,
29+
val type: KType,
30+
val source: KProperty1<*, *>
31+
)
32+
33+
val KType.memberProperties: List<KTypeProperty>
34+
get() {
35+
val typeParameters = jvmErasure.typeParameters.zip(arguments).associate { Pair(it.first.name, it.second.type) }
36+
return jvmErasure.memberProperties.map {
37+
val retType = it.returnType
38+
val properType = when (val classifier = retType.classifier) {
39+
is KTypeParameter -> typeParameters[classifier.name] ?: it.returnType
40+
else -> it.returnType
41+
}
42+
KTypeProperty(it.name, properType, it)
43+
}
44+
}
45+
46+
val KClass<*>.isInterface get() = java.isInterface

src/main/kotlin/com/papsign/ktor/openapigen/route/OpenAPIRoute.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import com.papsign.ktor.openapigen.modules.openapi.HandlerModule
1212
import com.papsign.ktor.openapigen.openAPIGen
1313
import com.papsign.ktor.openapigen.parameters.util.buildParameterHandler
1414
import com.papsign.ktor.openapigen.route.response.Responder
15-
import com.papsign.ktor.openapigen.validators.ValidationHandler
15+
import com.papsign.ktor.openapigen.validation.util.ValidationHandler
1616
import io.ktor.application.ApplicationCall
1717
import io.ktor.application.call
1818
import io.ktor.http.ContentType
@@ -40,8 +40,8 @@ abstract class OpenAPIRoute<T : OpenAPIRoute<T>>(val ktorRoute: Route, val provi
4040
it.configure(apiGen, provider)
4141
}
4242

43-
val BHandler = ValidationHandler<B>(provider)
44-
val PHandler = ValidationHandler<P>(provider)
43+
val BHandler = ValidationHandler.build<B>()
44+
val PHandler = ValidationHandler.build<P>()
4545

4646
ktorRoute.apply {
4747
getAcceptMap(R::class).let {

src/main/kotlin/com/papsign/ktor/openapigen/schema/builder/FinalSchemaBuilder.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ import com.papsign.ktor.openapigen.model.schema.SchemaModel
44
import com.papsign.ktor.openapigen.schema.builder.SchemaBuilder
55
import kotlin.reflect.KType
66

7-
interface FinalSchemaBuilder: SchemaBuilder {
8-
fun build(type: KType): SchemaModel<*>
7+
interface FinalSchemaBuilder {
8+
fun build(type: KType, annotations: List<Annotation> = listOf()): SchemaModel<*>
99
}

src/main/kotlin/com/papsign/ktor/openapigen/schema/builder/SchemaBuilder.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ interface SchemaBuilder {
1313
/**
1414
* @throws error when type is unexpected
1515
*/
16-
fun build(type: KType, builder: SchemaBuilder): SchemaModel<*>
16+
fun build(type: KType, builder: FinalSchemaBuilder): SchemaModel<*>
1717

1818
fun checkType(type: KType) {
1919
if (!type.isSubtypeOf(superType)) error("${this::class} cannot build type $type, only subtypes of $superType are supported")

src/main/kotlin/com/papsign/ktor/openapigen/schema/builder/provider/DefaultCollectionSchemaProvider.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import com.papsign.ktor.openapigen.getKType
66
import com.papsign.ktor.openapigen.model.schema.SchemaModel
77
import com.papsign.ktor.openapigen.modules.DefaultOpenAPIModule
88
import com.papsign.ktor.openapigen.modules.ModuleProvider
9+
import com.papsign.ktor.openapigen.schema.builder.FinalSchemaBuilder
910
import com.papsign.ktor.openapigen.schema.builder.SchemaBuilder
1011
import kotlin.reflect.KType
1112
import kotlin.reflect.full.withNullability
@@ -39,9 +40,9 @@ object DefaultCollectionSchemaProvider: SchemaBuilderProviderModule, OpenAPIGenM
3940

4041
private data class Builder(override val superType: KType, private val getter: (KType) -> KType) :
4142
SchemaBuilder {
42-
override fun build(type: KType, builder: SchemaBuilder): SchemaModel<*> {
43+
override fun build(type: KType, builder: FinalSchemaBuilder): SchemaModel<*> {
4344
checkType(type)
44-
return SchemaModel.SchemaModelArr<Any?>(builder.build(getter(type), builder), type.isMarkedNullable)
45+
return SchemaModel.SchemaModelArr<Any?>(builder.build(getter(type)), type.isMarkedNullable)
4546
}
4647
}
4748
}

src/main/kotlin/com/papsign/ktor/openapigen/schema/builder/provider/DefaultEnumSchemaProvider.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import com.papsign.ktor.openapigen.OpenAPIGenModuleExtension
55
import com.papsign.ktor.openapigen.getKType
66
import com.papsign.ktor.openapigen.model.schema.SchemaModel
77
import com.papsign.ktor.openapigen.modules.ModuleProvider
8+
import com.papsign.ktor.openapigen.schema.builder.FinalSchemaBuilder
89
import com.papsign.ktor.openapigen.schema.builder.SchemaBuilder
910
import kotlin.reflect.KType
1011
import kotlin.reflect.jvm.jvmErasure
@@ -13,7 +14,7 @@ object DefaultEnumSchemaProvider: SchemaBuilderProviderModule, OpenAPIGenModuleE
1314

1415
private object Builder: SchemaBuilder {
1516
override val superType: KType = getKType<Enum<*>>()
16-
override fun build(type: KType, builder: SchemaBuilder): SchemaModel<*> {
17+
override fun build(type: KType, builder: FinalSchemaBuilder): SchemaModel<*> {
1718
checkType(type)
1819
return SchemaModel.SchemaModelEnum<Any?>(
1920
type.jvmErasure.java.enumConstants.map { it.toString() },

src/main/kotlin/com/papsign/ktor/openapigen/schema/builder/provider/DefaultMapSchemaProvider.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import com.papsign.ktor.openapigen.OpenAPIGenModuleExtension
55
import com.papsign.ktor.openapigen.getKType
66
import com.papsign.ktor.openapigen.model.schema.SchemaModel
77
import com.papsign.ktor.openapigen.modules.ModuleProvider
8+
import com.papsign.ktor.openapigen.schema.builder.FinalSchemaBuilder
89
import com.papsign.ktor.openapigen.schema.builder.SchemaBuilder
910
import kotlin.reflect.KType
1011

@@ -16,13 +17,13 @@ object DefaultMapSchemaProvider: SchemaBuilderProviderModule, OpenAPIGenModuleEx
1617

1718
private object Builder : SchemaBuilder {
1819
override val superType: KType = getKType<Map<*, *>?>()
19-
override fun build(type: KType, builder: SchemaBuilder): SchemaModel<*> {
20+
override fun build(type: KType, builder: FinalSchemaBuilder): SchemaModel<*> {
2021
checkType(type)
2122
if (type.arguments[0].type != getKType<String>()) error("bad type $type: Only maps with string keys are supported")
2223
val valueType = type.arguments[1].type ?: error("bad type $type: star projected types are not supported")
2324
@Suppress("UNCHECKED_CAST")
2425
return SchemaModel.SchemaModelMap(
25-
builder.build(valueType, builder) as SchemaModel<Any?>,
26+
builder.build(valueType) as SchemaModel<Any?>,
2627
type.isMarkedNullable
2728
)
2829
}

src/main/kotlin/com/papsign/ktor/openapigen/schema/builder/provider/DefaultObjectSchemaProvider.kt

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,16 @@
11
package com.papsign.ktor.openapigen.schema.builder.provider
22

3-
import com.papsign.ktor.openapigen.OpenAPIGen
4-
import com.papsign.ktor.openapigen.OpenAPIGenModuleExtension
3+
import com.papsign.ktor.openapigen.*
54
import com.papsign.ktor.openapigen.classLogger
6-
import com.papsign.ktor.openapigen.getKType
75
import com.papsign.ktor.openapigen.model.schema.SchemaModel
86
import com.papsign.ktor.openapigen.modules.ModuleProvider
97
import com.papsign.ktor.openapigen.modules.ofClass
8+
import com.papsign.ktor.openapigen.schema.builder.FinalSchemaBuilder
109
import com.papsign.ktor.openapigen.schema.builder.SchemaBuilder
1110
import com.papsign.ktor.openapigen.schema.namer.DefaultSchemaNamer
1211
import com.papsign.ktor.openapigen.schema.namer.SchemaNamer
1312
import kotlin.reflect.KType
14-
import kotlin.reflect.KTypeParameter
1513
import kotlin.reflect.KVisibility
16-
import kotlin.reflect.full.declaredMemberProperties
17-
import kotlin.reflect.full.memberProperties
1814
import kotlin.reflect.full.starProjectedType
1915
import kotlin.reflect.full.withNullability
2016
import kotlin.reflect.jvm.jvmErasure
@@ -37,30 +33,28 @@ object DefaultObjectSchemaProvider : SchemaBuilderProviderModule, OpenAPIGenModu
3733

3834
private val refs = HashMap<KType, SchemaModel.SchemaModelRef<*>>()
3935

40-
override fun build(type: KType, builder: SchemaBuilder): SchemaModel<*> {
36+
override fun build(type: KType, builder: FinalSchemaBuilder): SchemaModel<*> {
4137
checkType(type)
4238
val nonNullType = type.withNullability(false)
4339
return refs[nonNullType] ?: {
4440
val erasure = nonNullType.jvmErasure
4541
val name = namer[nonNullType]
4642
val ref = SchemaModel.SchemaModelRef<Any?>("#/components/schemas/$name")
4743
refs[nonNullType] = ref // needed to prevent infinite recursion
48-
val existing = apiGen.api.components.schemas[name]
4944
val new = if (erasure.isSealed) {
50-
SchemaModel.OneSchemaModelOf(erasure.sealedSubclasses.map { builder.build(it.starProjectedType, builder) })
45+
SchemaModel.OneSchemaModelOf(erasure.sealedSubclasses.map { builder.build(it.starProjectedType) })
5146
} else {
52-
val typeParameters = erasure.typeParameters.zip(type.arguments).associate { Pair(it.first.name, it.second.type) }
53-
val memberMap = erasure.declaredMemberProperties.filter { it.visibility == KVisibility.PUBLIC }.associateWith {
54-
val retType = it.returnType
55-
when(val classifier = retType.classifier) {
56-
is KTypeParameter -> typeParameters[classifier.name] ?: it.returnType
57-
else -> it.returnType
58-
}
59-
}.mapKeys { (key, _) -> key.name }
60-
val required = memberMap.entries.filter { !it.value.isMarkedNullable }.map { it.key }
61-
val memberModels = memberMap.mapValues { (_, value) -> builder.build(value, builder) }
62-
SchemaModel.SchemaModelObj<Any?>(memberModels, required)
47+
val props = type.memberProperties.filter { it.source.visibility == KVisibility.PUBLIC }
48+
SchemaModel.SchemaModelObj<Any?>(
49+
props.associate {
50+
Pair(it.name, builder.build(it.type, it.source.annotations))
51+
},
52+
props.filter {
53+
!it.type.isMarkedNullable
54+
}.map { it.name }
55+
)
6356
}
57+
val existing = apiGen.api.components.schemas[name]
6458
if (existing != null && existing != new) log.error("Schema with name $name already exists, and is not the same as the new one, replacing...")
6559
apiGen.api.components.schemas[name] = new
6660
ref

0 commit comments

Comments
 (0)