Affects: 5.3.1
@Controller
class TestFetchController {
@Autowired
lateinit var repository: TestRepository
@RequestMapping("/categoriesfetch/", method = [RequestMethod.GET])
@ResponseBody
suspend fun categoriesGetFetched(
@RequestParam page: Int? = 0,
@RequestParam maxResults: Int? = 100
): ResponseEntity<*> {
val response: Page<Test> = repository.findAll(
PageRequest.of(page!!, maxResults!!)
)
val headers = Consumer<HttpHeaders> {
it.add("TotalElements", response.totalElements.toString())
it.add("TotalPages", response.totalPages.toString())
it.add("PerPage", response.numberOfElements.toString())
it.add("CurrentPage", response.number.toString())
}
return ResponseEntity.ok()
.contentType(MediaType.APPLICATION_JSON)
.headers(headers)
.body(response)
}
}
Returns the following response when using MockMvc:
Async:
Async started = true
Async result = <200 OK OK,[TestEntity(id=1, modificationDate=2020-11-13 10:04:07.613, modifierId=user, level=0, parentNode=null, displayName=Test0, relations=[]), TestEntity(id=2, modificationDate=2020-11-13 10:04:07.713, modifierId=user, level=0, parentNode=null, displayName=Test1, relations=[]), TestEntity(id=3, modificationDate=2020-11-13 10:04:07.719, modifierId=user, level=0, parentNode=null, displayName=Test2, relations=[]), TestEntity(id=4, modificationDate=2020-11-13 10:04:07.725, modifierId=user, level=0, parentNode=null, displayName=Test3, relations=[]), TestEntity(id=5, modificationDate=2020-11-13 10:04:07.73, modifierId=user, level=0, parentNode=null, displayName=Test4, relations=[])],[Content-Type:"application/json", TotalElements:"30", TotalPages:"6", PerPage:"5", CurrentPage:"0"]>
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 200
Error message = null
Headers = [X-Content-Type-Options:"nosniff", X-XSS-Protection:"1; mode=block", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Frame-Options:"DENY"]
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
The most interesting part IMO is the
[Content-Type:"application/json", TotalElements:"30", TotalPages:"6", PerPage:"5", CurrentPage:"0"]
and the missing body.
When removing the suspend keyword everything works as expected. The same applies when returning List
MockHttpServletResponse:
Status = 200
Error message = null
Headers = [X-Content-Type-Options:"nosniff", X-XSS-Protection:"1; mode=block", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Frame-Options:"DENY"]
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
Please note the missing body.
The MockMVC test:
@Test
@WithMockUser
fun `lazy loaded relationships are fetched via fetch`() {
val maxResults = 5
mockMvc.get("/categoriesfetch/?page=0&maxResults=$maxResults") {
header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
}.andExpect {
status { isOk() }
header {
string(PassHeaders.TOTALPAGES, "6")
string(PassHeaders.TOTALELEMENTS, "30")
string(PassHeaders.PERPAGE, "5")
string(PassHeaders.CURRENTPAGE, "0")
}
}.andReturn().response.contentAsString.let { body ->
val parsedCategories: List<TestEntity> = jacksonObjectMapper().readValue(body)
}
}
Please note: the request does work fine when actually running the Spring Boot app and querying the URL. The issue only applies within MockMVC tests.
Comment From: jonasbark
Apparently I have to add .asyncDispatch() to mockMvc.get(...) - sorry!