Skip to content

Commit eff84e9

Browse files
committed
Changed regex removal for spring on path parameters (Fixes #55)
1 parent 8b6372a commit eff84e9

File tree

3 files changed

+187
-7
lines changed

3 files changed

+187
-7
lines changed

spring/src/main/kotlin/de/codecentric/hikaku/converters/spring/SpringConverter.kt

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,17 +73,20 @@ class SpringConverter(private val applicationContext: ApplicationContext) : Abst
7373
}
7474

7575
private fun removeRegex(path: String): String {
76-
if (path.contains(':')) {
77-
return path.replace(Regex(":.*?}"), "}")
76+
return path.split('/').joinToString("/") { pathSegment ->
77+
pathSegment.let {
78+
when {
79+
it.contains(':') -> it.replace(Regex(":.*"), "}")
80+
else -> it
81+
}
82+
}
7883
}
79-
80-
return path
8184
}
8285

8386
private fun extractAvailableHttpMethods(mappingEntry: Map.Entry<RequestMappingInfo, HandlerMethod>): Set<HttpMethod> {
8487
val httpMethods = mappingEntry.key.hikakuHttpMethods()
8588

86-
// Spring adds all http methods except for trace if no http method has been set explicitly
89+
// Spring adds all http methods except for TRACE if no http method has been set explicitly
8790
// OPTIONS is a special case. If it's not added manually it has to be added without any path or query parameters
8891
return if (httpMethods.isEmpty()) {
8992
HttpMethod.values()
@@ -100,4 +103,4 @@ class SpringConverter(private val applicationContext: ApplicationContext) : Abst
100103
@JvmField
101104
val IGNORE_ERROR_ENDPOINT: (Endpoint) -> Boolean = { endpoint -> endpoint.path == "/error" }
102105
}
103-
}
106+
}

spring/src/test/kotlin/de/codecentric/hikaku/converters/spring/path/PathTestController.kt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,23 @@ open class RequestMappingOnClassProvidingRegexForPathVariableController {
3333
fun todo(@PathVariable(name = "id") variable: Int) { }
3434
}
3535

36+
@Controller
37+
@RequestMapping("/todos/{id:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}}", method = [GET])
38+
@Suppress("UNUSED_PARAMETER")
39+
open class RequestMappingOnClassProvidingComplexRegexForPathVariableController {
40+
41+
@RequestMapping
42+
fun todo(@PathVariable(name = "id") variable: Int) { }
43+
}
44+
45+
@Controller
46+
@Suppress("UNUSED_PARAMETER")
47+
open class RequestMappingOnClassProvidingMultipleRegexForPathVariableController {
48+
49+
@RequestMapping("/todos/{id:[0-9]+}/{title:[a-z]*}", method = [GET])
50+
fun todo(@PathVariable(name = "id",) variable: Int, @PathVariable(name = "title") title: String) { }
51+
}
52+
3653
@Controller
3754
open class RequestMappingOnFunctionWithMultiplePathsController {
3855

@@ -48,6 +65,22 @@ open class RequestMappingOnFunctionProvidingRegexForPathVariableController {
4865
fun todo(@PathVariable(name = "id") variable: Int) { }
4966
}
5067

68+
@Controller
69+
@Suppress("UNUSED_PARAMETER")
70+
open class RequestMappingOnFunctionProvidingComplexRegexForPathVariableController {
71+
72+
@RequestMapping("/todos/{id:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}}", method = [GET])
73+
fun todo(@PathVariable(name = "id") variable: Int) { }
74+
}
75+
76+
@Controller
77+
@Suppress("UNUSED_PARAMETER")
78+
open class RequestMappingOnFunctionProvidingMultipleRegexForPathVariableController {
79+
80+
@RequestMapping("/todos/{id:[0-9]+}/{title:[a-z]*}", method = [GET])
81+
fun todo(@PathVariable(name = "id") variable: Int, @PathVariable(name = "title") title: String) { }
82+
}
83+
5184
@Controller
5285
open class GetMappingOnFunctionWithMultiplePathsController {
5386

spring/src/test/kotlin/de/codecentric/hikaku/converters/spring/path/SpringConverterPathTest.kt

Lines changed: 145 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,78 @@ class SpringConverterPathTest {
114114
assertThat(implementation.conversionResult).containsExactlyInAnyOrderElementsOf(specification)
115115
}
116116
}
117+
118+
@Nested
119+
@WebMvcTest(RequestMappingOnClassProvidingComplexRegexForPathVariableController::class, excludeAutoConfiguration = [ErrorMvcAutoConfiguration::class])
120+
inner class RequestMappingOnClassProvidingComplexRegexForPathVariableTest {
121+
@Autowired
122+
lateinit var context: ConfigurableApplicationContext
123+
124+
@Test
125+
fun `endpoint having complex regex on path parameter using RequestMapping converts to a path without the regex`() {
126+
//given
127+
val specification: Set<Endpoint> = setOf(
128+
Endpoint(
129+
path = "/todos/{id}",
130+
httpMethod = GET,
131+
pathParameters = setOf(
132+
PathParameter("id")
133+
)
134+
),
135+
Endpoint(
136+
path = "/todos/{id}",
137+
httpMethod = HEAD,
138+
pathParameters = setOf(
139+
PathParameter("id")
140+
)
141+
),
142+
Endpoint("/todos/{id}", OPTIONS)
143+
)
144+
145+
//when
146+
val implementation = SpringConverter(context)
147+
148+
//then
149+
assertThat(implementation.conversionResult).containsExactlyInAnyOrderElementsOf(specification)
150+
}
151+
}
152+
153+
@Nested
154+
@WebMvcTest(RequestMappingOnClassProvidingMultipleRegexForPathVariableController::class, excludeAutoConfiguration = [ErrorMvcAutoConfiguration::class])
155+
inner class RequestMappingOnClassProvidingMutlipleRegexForPathVariableTest {
156+
@Autowired
157+
lateinit var context: ConfigurableApplicationContext
158+
159+
@Test
160+
fun `endpoint having complex regex on path parameter using RequestMapping converts to a path without the regex`() {
161+
//given
162+
val specification: Set<Endpoint> = setOf(
163+
Endpoint(
164+
path = "/todos/{id}/{title}",
165+
httpMethod = GET,
166+
pathParameters = setOf(
167+
PathParameter("id"),
168+
PathParameter("title"),
169+
)
170+
),
171+
Endpoint(
172+
path = "/todos/{id}/{title}",
173+
httpMethod = HEAD,
174+
pathParameters = setOf(
175+
PathParameter("id"),
176+
PathParameter("title"),
177+
)
178+
),
179+
Endpoint("/todos/{id}/{title}", OPTIONS)
180+
)
181+
182+
//when
183+
val implementation = SpringConverter(context)
184+
185+
//then
186+
assertThat(implementation.conversionResult).containsExactlyInAnyOrderElementsOf(specification)
187+
}
188+
}
117189
}
118190

119191
@Nested
@@ -179,6 +251,78 @@ class SpringConverterPathTest {
179251
assertThat(implementation.conversionResult).containsExactlyInAnyOrderElementsOf(specification)
180252
}
181253
}
254+
255+
@Nested
256+
@WebMvcTest(RequestMappingOnFunctionProvidingComplexRegexForPathVariableController::class, excludeAutoConfiguration = [ErrorMvcAutoConfiguration::class])
257+
inner class RequestMappingOnFunctionProvidingComplexRegexForPathVariableTest {
258+
@Autowired
259+
lateinit var context: ConfigurableApplicationContext
260+
261+
@Test
262+
fun `endpoint having complex regex on path parameter using RequestMapping converts to a path without the regex`() {
263+
//given
264+
val specification: Set<Endpoint> = setOf(
265+
Endpoint(
266+
path = "/todos/{id}",
267+
httpMethod = GET,
268+
pathParameters = setOf(
269+
PathParameter("id")
270+
)
271+
),
272+
Endpoint(
273+
path = "/todos/{id}",
274+
httpMethod = HEAD,
275+
pathParameters = setOf(
276+
PathParameter("id")
277+
)
278+
),
279+
Endpoint("/todos/{id}", OPTIONS)
280+
)
281+
282+
//when
283+
val implementation = SpringConverter(context)
284+
285+
//then
286+
assertThat(implementation.conversionResult).containsExactlyInAnyOrderElementsOf(specification)
287+
}
288+
}
289+
290+
@Nested
291+
@WebMvcTest(RequestMappingOnFunctionProvidingMultipleRegexForPathVariableController::class, excludeAutoConfiguration = [ErrorMvcAutoConfiguration::class])
292+
inner class RequestMappingOnFunctionProvidingMutlipleRegexForPathVariableTest {
293+
@Autowired
294+
lateinit var context: ConfigurableApplicationContext
295+
296+
@Test
297+
fun `endpoint having complex regex on path parameter using RequestMapping converts to a path without the regex`() {
298+
//given
299+
val specification: Set<Endpoint> = setOf(
300+
Endpoint(
301+
path = "/todos/{id}/{title}",
302+
httpMethod = GET,
303+
pathParameters = setOf(
304+
PathParameter("id"),
305+
PathParameter("title"),
306+
)
307+
),
308+
Endpoint(
309+
path = "/todos/{id}/{title}",
310+
httpMethod = HEAD,
311+
pathParameters = setOf(
312+
PathParameter("id"),
313+
PathParameter("title"),
314+
)
315+
),
316+
Endpoint("/todos/{id}/{title}", OPTIONS)
317+
)
318+
319+
//when
320+
val implementation = SpringConverter(context)
321+
322+
//then
323+
assertThat(implementation.conversionResult).containsExactlyInAnyOrderElementsOf(specification)
324+
}
325+
}
182326
}
183327
}
184328

@@ -633,4 +777,4 @@ class SpringConverterPathTest {
633777
}
634778
}
635779
}
636-
}
780+
}

0 commit comments

Comments
 (0)