Skip to content

Commit dcdf9c6

Browse files
Optional path parameter support
1 parent 87fd94f commit dcdf9c6

File tree

3 files changed

+52
-14
lines changed

3 files changed

+52
-14
lines changed

ksp-processor/jvm/src/dev/programadorthi/routing/ksp/RoutingProcessor.kt

Lines changed: 43 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import com.google.devtools.ksp.processing.SymbolProcessorProvider
1313
import com.google.devtools.ksp.symbol.FunctionKind
1414
import com.google.devtools.ksp.symbol.KSAnnotated
1515
import com.google.devtools.ksp.symbol.KSFunctionDeclaration
16+
import com.google.devtools.ksp.symbol.KSType
1617
import com.google.devtools.ksp.symbol.Visibility
1718
import com.squareup.kotlinpoet.FileSpec
1819
import com.squareup.kotlinpoet.FunSpec
@@ -85,22 +86,16 @@ private class RoutingProcessor(
8586
.firstOrNull()
8687
?.value
8788
?: paramName
88-
check(routeAnnotation.path.contains("{$customName}")) {
89+
val isOptional = routeAnnotation.path.contains("{$customName?}")
90+
val isRequired = routeAnnotation.path.contains("{$customName}")
91+
check(isOptional || isRequired) {
8992
"'$qualifiedName' has parameter '$paramName' that is not declared as path parameter {$customName}"
9093
}
91-
92-
val parsed = """$paramName = %M.parameters["$customName"]!!"""
93-
parameters += when (param.type.resolve()) {
94-
resolver.builtIns.booleanType -> "$parsed.toBoolean()"
95-
resolver.builtIns.byteType -> "$parsed.toByte()"
96-
resolver.builtIns.charType -> "$parsed[0]"
97-
resolver.builtIns.doubleType -> "$parsed.toDouble()"
98-
resolver.builtIns.floatType -> "$parsed.toFloat()"
99-
resolver.builtIns.intType -> "$parsed.toInt()"
100-
resolver.builtIns.longType -> "$parsed.toInt()"
101-
resolver.builtIns.shortType -> "$parsed.toInt()"
102-
resolver.builtIns.stringType -> parsed
103-
else -> error("Path parameters must be primitive type only")
94+
val paramType = param.type.resolve()
95+
val parsed = """$paramName = %M.parameters["$customName"]"""
96+
parameters += when {
97+
isOptional -> optionalParse(paramType, resolver, parsed)
98+
else -> requiredParse(paramType, resolver, parsed)
10499
}
105100
}
106101

@@ -133,4 +128,38 @@ private class RoutingProcessor(
133128
return emptyList()
134129
}
135130

131+
private fun optionalParse(
132+
paramType: KSType,
133+
resolver: Resolver,
134+
parsed: String
135+
) = when (paramType) {
136+
resolver.builtIns.booleanType.makeNullable() -> "$parsed?.toBooleanOrNull()"
137+
resolver.builtIns.byteType.makeNullable() -> "$parsed?.toByteOrNull()"
138+
resolver.builtIns.charType.makeNullable() -> "$parsed?.firstOrNull()"
139+
resolver.builtIns.doubleType.makeNullable() -> "$parsed?.toDoubleOrNull()"
140+
resolver.builtIns.floatType.makeNullable() -> "$parsed?.toFloatOrNull()"
141+
resolver.builtIns.intType.makeNullable() -> "$parsed?.toIntOrNull()"
142+
resolver.builtIns.longType.makeNullable() -> "$parsed?.toLongOrNull()"
143+
resolver.builtIns.shortType.makeNullable() -> "$parsed?.toShortOrNull()"
144+
resolver.builtIns.stringType.makeNullable() -> parsed
145+
else -> error("Path parameters must be primitive type only")
146+
}
147+
148+
private fun requiredParse(
149+
paramType: KSType,
150+
resolver: Resolver,
151+
parsed: String
152+
) = when (paramType) {
153+
resolver.builtIns.booleanType -> "$parsed!!.toBoolean()"
154+
resolver.builtIns.byteType -> "$parsed!!.toByte()"
155+
resolver.builtIns.charType -> "$parsed!!.first()"
156+
resolver.builtIns.doubleType -> "$parsed!!.toDouble()"
157+
resolver.builtIns.floatType -> "$parsed!!.toFloat()"
158+
resolver.builtIns.intType -> "$parsed!!.toInt()"
159+
resolver.builtIns.longType -> "$parsed!!.toLong()"
160+
resolver.builtIns.shortType -> "$parsed!!.toShort()"
161+
resolver.builtIns.stringType -> "$parsed!!"
162+
else -> optionalParse(paramType, resolver, parsed)
163+
}
164+
136165
}

samples/ksp-sample/src/main/kotlin/Main.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,8 @@ suspend fun main() {
1919
//router.call(name = "custom", parameters = parametersOf("random", "abc123"))
2020
router.call(uri = "/custom/${Random.Default.nextInt()}")
2121
delay(500)
22+
router.call(uri = "/optional")
23+
delay(500)
24+
router.call(uri = "/optional/ABC")
25+
delay(500)
2226
}

samples/ksp-sample/src/main/kotlin/dev/programadorthi/routing/sample/Routes.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ fun custom(@Path("random") value: String) {
2323
println(">>>> value: $value")
2424
}
2525

26+
@Route(path = "/optional/{id?}")
27+
fun optional(id: Char?) {
28+
println(">>>> Optional ID: $id")
29+
}
30+
2631
class Routes {
2732
//@Route("/path")
2833
fun run() {

0 commit comments

Comments
 (0)