Skip to content

Commit dd1438a

Browse files
committed
Changed module provider to handle synchronization in a more relaxed manner
Changed module provider to fix issue with erased types Changed Dependent module order, now are loaded before the type module that requires them, if and only if they are not already present Added type precision in the KType based module registration which erased types Changed dependent module registration to allow for generic specialized types without erasure by providing KType.
1 parent 1b1752a commit dd1438a

File tree

8 files changed

+71
-46
lines changed

8 files changed

+71
-46
lines changed
Lines changed: 27 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,45 @@
11
package com.papsign.ktor.openapigen.modules
22

33
import java.util.*
4+
import kotlin.collections.ArrayList
45
import kotlin.collections.LinkedHashSet
5-
import kotlin.reflect.KClass
66
import kotlin.reflect.KType
7-
import kotlin.reflect.full.starProjectedType
8-
import kotlin.reflect.full.superclasses
9-
10-
class CachingModuleProvider: ModuleProvider<CachingModuleProvider> {
11-
12-
@Synchronized
13-
override fun ofType(type: KType): Collection<Any> {
14-
return modules[type]?.toList() ?: listOf()
7+
import kotlin.reflect.full.isSubtypeOf
8+
import kotlin.reflect.full.isSupertypeOf
9+
10+
class CachingModuleProvider(previous: Iterable<Pair<KType, OpenAPIModule>> = listOf()) : ModuleProvider<CachingModuleProvider> {
11+
12+
private val modules: MutableList<Pair<KType, OpenAPIModule>> = Collections.synchronizedList( synchronized(previous) { previous.toMutableList() } )
13+
14+
override fun ofType(type: KType): Collection<OpenAPIModule> {
15+
val set = LinkedHashSet<OpenAPIModule>()
16+
synchronized(modules) {
17+
modules.filter {
18+
it.first.isSubtypeOf(type)
19+
}
20+
}.forEach {
21+
set.remove(it.second)
22+
set.add(it.second)
23+
}
24+
return set
1525
}
1626

17-
@Synchronized
1827
override fun registerModule(module: OpenAPIModule, type: KType) {
19-
registerModuleForClass(type, module)
2028
if (module is DependentModule) {
21-
module.handlers.forEach { registerModule(it, it::class.starProjectedType) }
29+
module.handlers.forEach { (depType, depModule) ->
30+
if (synchronized(modules) { modules.find { it.second == depModule } } == null) {
31+
registerModule(depModule, depType)
32+
}
33+
}
2234
}
35+
modules.add(type to module)
2336
}
2437

25-
@Synchronized
2638
override fun unRegisterModule(module: OpenAPIModule) {
27-
modules.values.forEach { it.remove(module) }
28-
}
29-
30-
@Synchronized
31-
private fun registerModuleForClass(type: KType, module: OpenAPIModule) {
32-
val lst = modules.getOrPut(type) {LinkedHashSet()}
33-
lst.remove(module)
34-
lst.add(module)
35-
(type.classifier as KClass<*>).supertypes.forEach {
36-
registerModuleForClass(it, module)
37-
}
39+
synchronized(modules) { modules.removeIf { it.second == module } }
3840
}
3941

40-
private val modules = HashMap<KType, LinkedHashSet<OpenAPIModule>>()
41-
42-
@Synchronized
4342
override fun child(): CachingModuleProvider {
44-
val new = CachingModuleProvider()
45-
modules.forEach { (t: KType, u) ->
46-
new.modules[t] = LinkedHashSet(u)
47-
}
48-
return new
43+
return CachingModuleProvider(modules)
4944
}
5045
}
Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
package com.papsign.ktor.openapigen.modules
22

3+
import com.papsign.ktor.openapigen.getKType
4+
import kotlin.reflect.KType
5+
36
interface DependentModule {
4-
val handlers: Collection<OpenAPIModule>
5-
}
7+
val handlers: Collection<Pair<KType, OpenAPIModule>>
8+
9+
companion object {
10+
inline fun <reified T: OpenAPIModule> handler(handler: T): Pair<KType, T> {
11+
return getKType<T>() to handler
12+
}
13+
}
14+
}

src/main/kotlin/com/papsign/ktor/openapigen/modules/providers/AuthProvider.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,21 @@ package com.papsign.ktor.openapigen.modules.providers
33
import com.papsign.ktor.openapigen.model.Described
44
import com.papsign.ktor.openapigen.model.security.SecuritySchemeModel
55
import com.papsign.ktor.openapigen.modules.DependentModule
6+
import com.papsign.ktor.openapigen.modules.DependentModule.Companion.handler
67
import com.papsign.ktor.openapigen.modules.OpenAPIModule
78
import com.papsign.ktor.openapigen.modules.handlers.AuthHandler
89
import com.papsign.ktor.openapigen.route.path.auth.OpenAPIAuthenticatedRoute
910
import com.papsign.ktor.openapigen.route.path.normal.NormalOpenAPIRoute
1011
import io.ktor.application.ApplicationCall
1112
import io.ktor.util.pipeline.PipelineContext
13+
import kotlin.reflect.KType
1214

1315
interface AuthProvider<TAuth>: OpenAPIModule, DependentModule {
1416
suspend fun getAuth(pipeline: PipelineContext<Unit, ApplicationCall>): TAuth
1517
fun apply(route: NormalOpenAPIRoute): OpenAPIAuthenticatedRoute<TAuth>
1618
val security: Iterable<Iterable<Security<*>>>
17-
override val handlers: Collection<OpenAPIModule>
18-
get() = listOf(AuthHandler)
19+
override val handlers: Collection<Pair<KType, OpenAPIModule>>
20+
get() = listOf(handler(AuthHandler))
1921

2022
data class Security<TScope>(val scheme: SecuritySchemeModel<TScope>, val requirements: List<TScope>) where TScope: Enum<TScope>, TScope: Described
2123
}
Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
package com.papsign.ktor.openapigen.modules.providers
22

3+
import com.papsign.ktor.openapigen.getKType
34
import com.papsign.ktor.openapigen.modules.DependentModule
5+
import com.papsign.ktor.openapigen.modules.DependentModule.Companion.handler
46
import com.papsign.ktor.openapigen.modules.OpenAPIModule
57
import com.papsign.ktor.openapigen.modules.handlers.RouteHandler
68
import io.ktor.http.HttpMethod
9+
import kotlin.reflect.KType
710

811
interface MethodProvider : OpenAPIModule, DependentModule {
912
val method: HttpMethod
10-
override val handlers: Collection<OpenAPIModule>
11-
get() = listOf(RouteHandler)
12-
}
13+
override val handlers: Collection<Pair<KType, OpenAPIModule>>
14+
get() = listOf(handler(RouteHandler))
15+
}
Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
package com.papsign.ktor.openapigen.modules.providers
22

33
import com.papsign.ktor.openapigen.APITag
4+
import com.papsign.ktor.openapigen.getKType
45
import com.papsign.ktor.openapigen.modules.DependentModule
6+
import com.papsign.ktor.openapigen.modules.DependentModule.Companion.handler
57
import com.papsign.ktor.openapigen.modules.OpenAPIModule
68
import com.papsign.ktor.openapigen.modules.RouteOpenAPIModule
79
import com.papsign.ktor.openapigen.modules.handlers.TagHandlerModule
10+
import kotlin.reflect.KType
811

912
interface TagProviderModule: RouteOpenAPIModule, DependentModule {
1013
val tags: Collection<APITag>
11-
override val handlers: Collection<OpenAPIModule>
12-
get() = listOf(TagHandlerModule)
14+
override val handlers: Collection<Pair<KType, OpenAPIModule>>
15+
get() = listOf(handler(TagHandlerModule))
1316
}

src/main/kotlin/com/papsign/ktor/openapigen/modules/providers/ThrowInfoProvider.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ package com.papsign.ktor.openapigen.modules.providers
22

33
import com.papsign.ktor.openapigen.APIException
44
import com.papsign.ktor.openapigen.modules.DependentModule
5+
import com.papsign.ktor.openapigen.modules.DependentModule.Companion.handler
56
import com.papsign.ktor.openapigen.modules.OpenAPIModule
67
import com.papsign.ktor.openapigen.modules.handlers.ThrowOperationHandler
8+
import kotlin.reflect.KType
79

810
interface ThrowInfoProvider: OpenAPIModule, DependentModule {
911
val exceptions: List<APIException<*, *>>
10-
override val handlers: Collection<OpenAPIModule>
11-
get() = listOf(ThrowOperationHandler)
12+
override val handlers: Collection<Pair<KType, OpenAPIModule>>
13+
get() = listOf(handler(ThrowOperationHandler))
1214
}

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.papsign.ktor.openapigen.route
33
import com.papsign.ktor.openapigen.APITag
44
import com.papsign.ktor.openapigen.annotations.Path
55
import com.papsign.ktor.openapigen.content.type.ContentTypeProvider
6+
import com.papsign.ktor.openapigen.getKType
67
import com.papsign.ktor.openapigen.modules.handlers.RequestHandlerModule
78
import com.papsign.ktor.openapigen.modules.handlers.ResponseHandlerModule
89
import com.papsign.ktor.openapigen.modules.registerModule
@@ -13,7 +14,11 @@ import io.ktor.routing.HttpMethodRouteSelector
1314
import io.ktor.routing.createRouteFromPath
1415
import io.ktor.util.pipeline.ContextDsl
1516
import kotlin.reflect.KType
17+
import kotlin.reflect.KTypeProjection
18+
import kotlin.reflect.KVariance
19+
import kotlin.reflect.full.createType
1620
import kotlin.reflect.full.findAnnotation
21+
import kotlin.reflect.full.starProjectedType
1722
import kotlin.reflect.jvm.jvmErasure
1823
import kotlin.reflect.typeOf
1924

@@ -141,13 +146,15 @@ internal fun <TParams : Any, TResponse : Any, TRequest : Any, TRoute : OpenAPIRo
141146
RequestHandlerModule.create(
142147
bType,
143148
exampleRequest
144-
)
149+
),
150+
RequestHandlerModule::class.createType(listOf(KTypeProjection(KVariance.INVARIANT, bType)))
145151
)
146152
provider.registerModule(
147153
ResponseHandlerModule.create(
148154
rType,
149155
exampleResponse
150-
)
156+
),
157+
ResponseHandlerModule::class.createType(listOf(KTypeProjection(KVariance.INVARIANT, rType)))
151158
)
152159
if (path != null) {
153160
provider.registerModule(PathProviderModule(path.path))

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import com.papsign.ktor.openapigen.modules.ofType
1111
import com.papsign.ktor.openapigen.modules.openapi.HandlerModule
1212
import com.papsign.ktor.openapigen.modules.registerModule
1313
import com.papsign.ktor.openapigen.openAPIGen
14+
import com.papsign.ktor.openapigen.parameters.handlers.ParameterHandler
1415
import com.papsign.ktor.openapigen.parameters.util.buildParameterHandler
1516
import com.papsign.ktor.openapigen.route.response.Responder
1617
import com.papsign.ktor.openapigen.validation.ValidationHandler
@@ -24,6 +25,9 @@ import io.ktor.routing.application
2425
import io.ktor.routing.contentType
2526
import io.ktor.util.pipeline.PipelineContext
2627
import kotlin.reflect.KType
28+
import kotlin.reflect.KTypeProjection
29+
import kotlin.reflect.KVariance
30+
import kotlin.reflect.full.createType
2731

2832
abstract class OpenAPIRoute<T : OpenAPIRoute<T>>(val ktorRoute: Route, val provider: CachingModuleProvider) {
2933
private val log = classLogger()
@@ -37,7 +41,7 @@ abstract class OpenAPIRoute<T : OpenAPIRoute<T>>(val ktorRoute: Route, val provi
3741
pass: suspend OpenAPIRoute<*>.(pipeline: PipelineContext<Unit, ApplicationCall>, responder: Responder, P, B) -> Unit
3842
) {
3943
val parameterHandler = buildParameterHandler<P>(paramsType)
40-
provider.registerModule(parameterHandler)
44+
provider.registerModule(parameterHandler, ParameterHandler::class.createType(listOf(KTypeProjection(KVariance.INVARIANT, paramsType))))
4145

4246
val apiGen = ktorRoute.application.openAPIGen
4347
provider.ofType<HandlerModule>().forEach {

0 commit comments

Comments
 (0)