I have test that works properly with Spring 2.4.0-M2 but after upgrading to 2.4.0-M3 it breaks - returns 404 for a route that is registered.
My app:
@SpringBootApplication(proxyBeanMethods = false)
class ExampleApp
fun main(args: Array<String>) {
runApplication<ExampleApp>(
init = {
addInitializers(BeansInitializer())
},
args = args
)
}
beans:
class BeansInitializer : ApplicationContextInitializer<GenericApplicationContext> {
@Suppress("LongMethod")
override fun initialize(applicationContext: GenericApplicationContext) {
beans {
bean {
router {
"/routes".nest {
GET("/{id}") { ServerResponse.ok().bodyValue(Foo("ok")) }
POST("/") { ServerResponse.ok().bodyValue(Foo("ok")) }
}
}
}
}
.initialize(applicationContext)
}
}
data class Foo(val status: String)
My test:
@SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = [
ExampleApp::class
]
)
class FailingTest @Autowired constructor(
context: ApplicationContext,
) {
val webTestClient: WebTestClient = WebTestClient.bindToApplicationContext(context)
.configureClient()
.build()
@Test
fun `should interact with routes`() {
webTestClient
.post()
.uri("/routes")
.bodyValue(SampleBody("123"))
.exchange()
.expectStatus()
.isOk // returns 404 on 2.4.0-M3 / passes on 2.4.0-M2
}
data class SampleBody(val id: String)
}
test application.yml
context:
initializer:
classes: com.example.BeansInitializer
On 2.4.0-M3
tests fail with following message:
java.lang.AssertionError: Status expected:<200 OK> but was:<404 NOT_FOUND>
On 2.4.0-M2
they pass.
Is there something that changed through the versions? Or this is a bug?
The change in behaviour that you are seeing is due to an improvement in Spring Framework during the development of 5.3.
By default, Spring Framework will match an optional trailing path separator (/
). This optional /
should be in addition to the path specified in your routes.
You have two routes:
GET /routes/{id}
POST /routes/
The support for an optional trailing path separator means that you could make a get request to /routes/56/
(an additional trailing /
), but it should not mean that you can make a request to POST /routes
(removal of a trailing /
).
If you want to be able to make POST
requests to both /routes
and /routes/
, you should define the route as /routes
:
beans {
bean {
router {
"/routes".nest {
GET("/{id}") { ServerResponse.ok().bodyValue(Foo("ok")) }
POST("") { ServerResponse.ok().bodyValue(Foo("ok")) }
}
}
}
}