#WebMvcTest Found Status 404 And Service return null - spring-boot

When I use #WebMvcTest to test my Spring Controller, I meet two questions.
MockMvc can't find right URL
After I add MockMvcBuilders.standaloneSetup(), mockMvc was worked.But My Controller throw NullPointException caused by #Autowired Service
I just do unit-test, so I don't want to use #SpringBootTest to starup all my SpringBoot Aplication.
I have try to #InjectMock My Controller and #Mock or #MockBean Service.The are all didn't work.
So could someone tell me why #Autowired mockMvc can't find the Controller and how to mock inner #Autowired filed in Spock unit test without #SpringBootTest?
Here are my controller
#RestController
#RequestMapping("/schedule/filter")
public class ScheduleObjectFilterController extends BaseController {
#PostMapping(path="/",produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public String createScheduleObjectFilter(#RequestBody String body){
BaseResponse<ResponseStatus> resp = new BaseResponse<>(ResponseStatus._200);
try{
List<ScheduleObjectFilterParam> paramList = parseJSONArray(body,ScheduleObjectFilterParam.class);
resp.setStatus(scheduleObjectFilterService.createScheduleObjectFilter(paramList));
}catch(BaseRuntimeException e){
logger.error("Create ScheduleObjectFilter error:", e);
resp.setException(e);
}catch(Exception e){
logger.error("Create ScheduleObjectFilter error:", e);
resp.setStatus(ResponseStatus._500);
}
return renderJSON(resp);
}
#Autowired
private ScheduleObjectFilterService scheduleObjectFilterService;
}
Here are my Service and it's implement
public interface ScheduleObjectFilterService{
ResponseStatus createScheduleObjectFilter(List<ScheduleObjectFilterParam> paramList);
}
#Service
public class ScheduleObjectFilterServiceImpl extends BaseService implements ScheduleObjectFilterService {
public ResponseStatus createScheduleObjectFilter(List<ScheduleObjectFilterParam> paramList) {
// some code
}
}
Here is my test class
#WebMvcTest(controllers = [ScheduleObjectFilterController.class])
#ActiveProfiles("local")
class ScheduleSettingControllerSpecification extends Specification{
#Autowired
MockMvc mockMvc
#MockBean
BaseController baseController
#MockBean
ScheduleObjectFilterService scheduleObjectFilterService
def setup(){
//after add next line,the mockMvc can find url,but service throw NullPointException
//mockMvc = MockMvcBuilders.standaloneSetup(new ScheduleObjectFilterController()).build()
scheduleObjectFilterService.createScheduleObjectFilter(_ as List) >> ResponseStatus._500
}
def "MvcTest"(){
given:
ScheduleObjectFilterParam param = new ScheduleObjectFilterParam()
List<ScheduleObjectFilterParam> dataList = Collections.singletonList(param)
expect:
mockMvc.perform(post("/schedule/filter/").contentType(MediaType.APPLICATION_JSON).content(JSONObject.toJSONString(dataList)))
.andExpect(status().isOk())
}
}
before add MockMvcBuilders.standaloneSetup():
MockHttpServletRequest:
HTTP Method = POST
Request URI = /schedule/filter/
Parameters = {}
Headers = {Content-Type=[application/json]}
Body = <no character encoding set>
Session Attrs = {}
Handler:
Type = org.springframework.web.servlet.resource.ResourceHttpRequestHandler
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 404
Error message = null
Headers = {}
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
After add That:
2019-11-10 11:53:22.896 [WEB] [ERROR] com.kaifa.hes.schedule.controller.ScheduleObjectFilterController.createScheduleObjectFilter() -> Create ScheduleObjectFilter error:
java.lang.NullPointerException: null
at com.kaifa.hes.schedule.controller.ScheduleObjectFilterController.createScheduleObjectFilter(ScheduleObjectFilterController.java:47) [classes/:?]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_201]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_201]
......
this exception direct to this line in controller
resp.setStatus(scheduleObjectFilterService.createScheduleObjectFilter(paramList));

#WebMvcTest is only used to test the web layer by application, so you need to mock any dependencies in controller and stub the method call. more information
#WebMvcTest(controllers = [ScheduleObjectFilterController.class])
#ActiveProfiles("local")
class ScheduleSettingControllerSpecification extends Specification{
#Autowired
MockMvc mockMvc
#MockBean
BaseController baseController
#MockBean
ScheduleObjectFilterService scheduleObjectFilterService
def "MvcTest"(){
when(this.scheduleObjectFilterService.createScheduleObjectFilter(ArgumentMatchers.anyList())
.thenReturn(// custom error);
given:
ScheduleObjectFilterParam param = new ScheduleObjectFilterParam()
List<ScheduleObjectFilterParam> dataList = Collections.singletonList(param)
expect:mockMvc.perform(post("/schedule/filter/").contentType(MediaType.APPLICATION_JSON).content(JSONObject.toJSONString(dataList)))
.andExpect(status().isOk())
}
}

#InjectMocks can't work in Spock. If we want to use the same function,here has a third-part extension
We can use the #Subject and #Collaborator annotation to solve this problem.
Pay attention,Spock has its own #Subject annotation.Before import the package,please check if it in correct packages

Related

MockMvc with SpringBootTest is throwing exception HttpMediaTypeNotSupportedException when testing the controller

I am testing request validation in Spring RestController with the help of integration testing and MockMvc.
ControllerTest.java
#ExtendWith(MockitoExtension.class)
#SpringBootTest(classes = Controller.class)
#AutoConfigureMockMvc(addFilters = false)
class ControllerTest {
private ObjectMapper objectMapper;
#MockBean
private Service service;
#Autowired
private MockMvc mockMvc;
#BeforeEach
void setUp() {
objectMapper = new ObjectMapper();
}
#Test
void createOrAdd_shouldReturnErrorResponseOnInvalidInput() throws Exception {
Request request = Request.builder()
.name("name<script>")
.primaryEmail("test#mail.com")
.build();
mockMvc.perform(MockMvcRequestBuilders.post("/api/create")
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON_VALUE)
.content(objectMapper.writeValueAsString(request))
.characterEncoding("utf-8"))
.andExpect(MockMvcResultMatchers.status().isBadRequest());
}
}
Controller.java :
#Slf4j
#RestController
public class Controller {
private final Service service;
public Controller(Service service) {
this.service = service;
}
#PostMapping(value = "/api/create", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<GenericResponse<Response>> createOrAdd(#RequestBody #Valid Request request, Errors errors) {
GenericResponse<Response> genericResponse = new GenericResponse<>();
try {
if (errors.hasErrors()) {
throw new RequestParamsException(errors.getAllErrors());
}
Response response = service.createOrAdd(request);
genericResponse.setData(response);
return ResponseEntity.ok().body(genericResponse);
} catch (RequestParamsException ex) {
genericResponse.setErrors(ex.getErrors());
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(genericResponse);
}
}
Error :
WARN 17304 --- [ main] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/json;charset=utf-8' not supported]
MockHttpServletRequest:
HTTP Method = POST
Request URI = /api/create
Parameters = {}
Headers = [Content-Type:"application/json;charset=utf-8", Accept:"application/json", Content-Length:"162"]
Body = {"name":"name<script>alert(1)</script>","primary_email_address":"test#mail.com"}
Session Attrs = {}
Handler:
Type = com.org.controller.Controller
Method = com.org.controller.Controller#createOrAdd(Request, Errors)
Async:
Async started = false
Async result = null
Resolved Exception:
Type = org.springframework.web.HttpMediaTypeNotSupportedException
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 415
Error message = null
Headers = [Accept:"application/octet-stream, text/plain, application/xml, text/xml, application/x-www-form-urlencoded, application/*+xml, multipart/form-data, multipart/mixed, */*"]
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
java.lang.AssertionError: Status expected:<400> but was:<415>
Expected :400
Actual :415
I have used the correct Content-Type and Accept Headers while making a call in Test.java using mockMvc, but still it's giving HttpMediaTypeNotSupportedException. Tried many combinations in Accept and Content-Type but still not working.
I have read many SO questions related to this exception, but couldn't find what's the issue here.
Still not able to figure out why it's saying HttpMediaTypeNotSupportedException.
Update : After removing addFilters = false as suggested, not able to find the handler itself.
MockHttpServletRequest:
HTTP Method = POST
Request URI = /api/create
Parameters = {}
Headers = [Content-Type:"application/json;charset=utf-8", Accept:"application/json", Content-Length:"162"]
Body = {"name":"name<script>alert(1)</script>","primary_email_address":"test#mail.com"}
Session Attrs = {org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.CSRF_TOKEN=org.springframework.security.web.csrf.DefaultCsrfToken#7a687d8d}
Handler:
Type = null
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 403
Error message = Forbidden
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 = []
java.lang.AssertionError: Status expected:<400> but was:<403>
Expected :400
Actual :403
Request :
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
#JsonIgnoreProperties(ignoreUnknown = true)
#JsonInclude(JsonInclude.Include.NON_NULL)
public class CreateAgencyRequest {
#NotNull(message = "name can't be null")
#JsonProperty(value = "name")
#Pattern(regexp = REGEX_CONST, message = "name is not valid")
private String name;
#NotNull(message = "primary_email_address can't be null")
#JsonProperty(value = "primary_email_address")
private String primaryEmail;
}
Lets take a look at your test.
#WebMvcTest(classes = Controller.class)
#AutoConfigureMockMvc(addFilters = false)
class ControllerTest {
private ObjectMapper objectMapper;
#MockBean
private Service service;
#Autowired
private MockMvc mockMvc;
#Test
void createOrAdd_shouldReturnErrorResponseOnInvalidInput() throws Exception {
Request request = Request.builder()
.name("name<script>")
.primaryEmail("test#mail.com")
.build();
mockMvc.perform(MockMvcRequestBuilders.post("/api/create")
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON_VALUE)
.content(objectMapper.writeValueAsString(request))
.characterEncoding("utf-8"))
.andExpect(MockMvcResultMatchers.status().isBadRequest());
}
}
First the #ExtendWith(MockitoExtension.class) doesn't add anything as you are using, correctly, the #MockBean annotation which is handled by Spring. So you should remove that.
Next the #SpringBootTest is for bootstrapping the full application to run an integration test. What you want is a sliced test for the web, so instead of #SpringBootTest use #WebMvcTest this will make your test considerably faster. You can then also remove #AutoConfigureMockMvc as that is added by default.
You disabled all filters with #AutoConfigureMockMvc(addFilters = false) probably due to the 403 you got. The 403 you have is the result of enabling CSRF (enabled by default) and not adding that to the request. If you don't want CSRF (you probably want it) either disable that in the Security configuration, or if you want it modify your request.
Looking at the error you have the culprit is the characterEncoding being added to the content type, so you probably want/should remove that.
With all that your test should look something like this.
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*;
#WebMvcTest(Controller.class)
class ControllerTest {
private ObjectMapper objectMapper = new ObjectMapper();
#MockBean
private Service service;
#Autowired
private MockMvc mockMvc;
#Test
void createOrAdd_shouldReturnErrorResponseOnInvalidInput() throws Exception {
Request request = Request.builder()
.name("name<script>")
.primaryEmail("test#mail.com")
.build();
mockMvc.perform(MockMvcRequestBuilders.post("/api/create")
.with(csrf()) // Add CSRF field for security
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON_VALUE)
.content(objectMapper.writeValueAsString(request))
.andExpect(MockMvcResultMatchers.status().isBadRequest());
}
}
NOTE: If you also have authentication in place you might also need to add a user/password to the request as explained here
I think you are missing #WebMvcTest(controllers = Controller.class)

Validating if request body in HTTP POST request is null in Spring Boot controller

I am replacing manual validation of input to a POST request in a Spring Boot REST-controller. JSR-303 Spring Bean Validation is used for validating the instance variables in the request body and this is working as expected. What is the recommended method to validate that the object in the request body is not null?
I have tried:
annotating the entire object such as this: #NotNull #Valid #RequestBody Foo foo
annotating the entire class with #NotNull
I am replacing:
#PostMapping...
public ResponseEntity<Map<String, Object>> editFoo(
#RequestBody Foo foo, ...) {
if(foo == null) {
return (new ResponseEntity<>(headers, HttpStatus.BAD_REQUEST));
}
}
with a Bean Validation equivalent:
#PostMapping...
public ResponseEntity<Map<String, Object>> editFoo(
#Valid #RequestBody Foo foo, ...) {
...
}
I tried unit testing the controller method by:
// Arrange
Foo foo = null;
String requestBody = objectMapper.writeValueAsString(foo);
// Act + assert
mockMvc
.perform(
post("/end_point")
.contentType("application/json")
.content(requestBody))
.andExpect(status().isBadRequest());
I expected a MethodArgumentNotValidException which is handled by a #ControllerAdvice for this exception, but I get HttpMessageNotReadableException when executing the unit test.
My questions:
is it necessary to test if the request body is null?
if 1. is true, how should this be done with Bean Validation?
Seeing your code, you already check if the body is null. In fact #RequestBody has a default parameter required which defaults to true. So no need for Bean validation for that !
Your main issue here seems to be in your test. First of all it is good to write a test to validate your endpoint behavior on null.
However, in your test you does not pass null. You try to create a Json object from a null value with your objectMapper.
The object you are writting seems not to be a valid json. So when your sending this body, Spring says that it cannot read the message, aka the body of your request, as you say it is a application/json content but there is not json in it.
To test null body, just send your request in your test just removing the .content(requestBody) line and it should work !
--- Edit 1
I thought it was rejecting the message because of the body, but in fact it seems to work right away for me. Here is my controler and test so you can compare to your full code :
#RestController()
#RequestMapping("end_point")
public class TestController {
#PostMapping
public ResponseEntity<Map<String, Object>> editFoo(#RequestBody Foo foo) {
// if(foo == null) {
// return (new ResponseEntity<>(new HashMap<>(), HttpStatus.BAD_REQUEST));
// }
return (new ResponseEntity<>(new HashMap<>(), HttpStatus.OK));
}
}
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#AutoConfigureMockMvc
public class TestControllerTest {
#Autowired
private MockMvc mvc;
#Autowired
private ObjectMapper objectMapper;
#Test
public void test_body_is_null() throws Exception {
Foo foo = null;
String requestBody = objectMapper.writeValueAsString(foo);
// Act + assert
mvc
.perform(
post("/end_point")
.contentType("application/json")
.content(requestBody))
.andExpect(status().isBadRequest());
}
}
This was made using Spring Boot 2.1.6.RELEASE
--- Edit 2
For the record if you want to use validation for null here, here is a snippet of the controller :
#RestController()
#RequestMapping("end_point")
#Validated
public class TestController {
#PostMapping
public ResponseEntity<Map<String, Object>> editFoo(#NotNull #RequestBody(required = false) Foo foo) {
return (new ResponseEntity<>(new HashMap<>(), HttpStatus.OK));
}
}
First you have to set required to false for the body, as default is true. Then you have to add the #NotNull annotation on the request body and #Validated on the controller.
Here if you launch your test you will see that the request fails with :
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is javax.validation.ConstraintViolationException: editFoo.foo: must not be null
As you said you had a #ControllerAdvice you can then map the exception as you wish !

Spring runner test return 404 for API test

I am writing API test cases for one of my controllers, but it is resulting with a 404.
I thought it would be a typo but it is not. Below are the code snippets.
RestController: package: com.x.y.address.controller (src/main)
#RestController
public class AddressInternalController {
#PostMapping(value = "/v1/address-service/internal/company/address", produces = "application/json;charset=UTF-8")
#ResponseStatus(OK)
public #ResponseBody ResponseEntity<AddressModel> createCompanyAddress()
throws AddressException, BadRequestException {
return ok("SUCCESS");
}
}
My Test class: package com.x.y.address.controller (src/test)
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = TestApp.class, initializers = ConfigFileApplicationContextInitializer.class)
#WebMvcTest(controllers = AddressInternalController.class, secure = false)
public class AddressInternalControllerTest {
#Autowired
private MockMvc mvc;
#Before
public void init() {}
#Test
public void createAddressTest_when_invalid_company() throws Exception {
this.mvc.perform(post("/v1/address-service/internal/company/address").contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}
}
My app uses spring security and to bypass that I have created a TestAPP class so that it will help me build only the config without security.
TestApp: package com.x.y.address (src/test)
#EnableAutoConfiguration(exclude = { SecurityAutoConfiguration.class})
// #ComponentScan({"com.x.y.address.controller.AddressInternalController"})
public class TestApp {
}
Above are the structure of the class.
Initially I thought may be the program does not scan the controller package and hence the 404. Hence added the componentScan. But that did not help.
Searched through a lot of stack over flow but most of the 404 are due to a type but it is not in my case.
Error log:
MockHttpServletRequest:
HTTP Method = POST
Request URI = /v1/address-service/internal/company/address
Parameters = {}
Headers = {Content-Type=[application/json]}
Body = <no character encoding set>
Session Attrs = {}
Handler:
Type = org.springframework.web.servlet.resource.ResourceHttpRequestHandler
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 404
Error message = null
Headers = {}
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
java.lang.AssertionError: Status
Expected :200
Actual :404
Any help shall be greatly appreciated.
I replaced:
#EnableAutoConfiguration(exclude = { SecurityAutoConfiguration.class})
// #ComponentScan({"com.x.y.address.controller.AddressInternalController"})
public class TestApp {
}
with:
#SpringBootApplication(exclude = { SecurityAutoConfiguration.class})
// #ComponentScan({"com.x.y.address.controller.AddressInternalController"})
public class TestApp {
}
and it worked.
UPDATE 1:
I noticed, in your #ComponentScan you use the path to the class itself, but you should point to the package with your controller. If you want to specify a class, use basePackageClasses property of #ComponentScan

"Could not find acceptable representation" when testing spring download link with MockMvc

I have a controller that should allow downloading files with arbitrary content type:
#GetMapping(value="/download/{directory}/{name}",
consumes=MediaType.ALL_VALUE)
#Timed
public ResponseEntity<byte[]> downloadFile(#PathVariable String directory,
#PathVariable String name) {
log.debug("REST request to download File : {}/{}", directory, name);
byte[] content = "it works".getBytes();
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_TYPE, "text/plain");
return new ResponseEntity<>(content, headers, HttpStatus.OK);
}
I want to test that in a unit test like this:
...
private MockMvc restFileMockMvc;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
final FileResource fileResource = new FileResource(fileService);
this.restFileMockMvc = MockMvcBuilders.standaloneSetup(fileResource)
.setCustomArgumentResolvers(pageableArgumentResolver)
.setControllerAdvice(exceptionTranslator)
.setConversionService(createFormattingConversionService())
.setMessageConverters(jacksonMessageConverter)
.setValidator(validator).build();
}
#Test
#Transactional
public void downloadFile() throws Exception {
String url = "/api/download/it/works.txt";
restFileMockMvc.perform(get(url).header(HttpHeaders.ACCEPT, "*/*"))
.andDo(MockMvcResultHandlers.print()) // Debugging only!
.andExpect(status().isOk());
}
But obviously, there is a problem with the content type, resp. the accept header. MockMvcResultHandlers.print() produces the following:
MockHttpServletRequest:
HTTP Method = GET
Request URI = /api/download/DIRDIR/NAMENAME
Parameters = {}
Headers = {Accept=[*/*]}
Body = <no character encoding set>
Session Attrs = {}
Handler:
Type = com.example.storage.web.rest.FileResource
Method = public org.springframework.http.ResponseEntity<byte[]> com.example.storage.web.rest.FileResource.downloadFile(java.lang.String,java.lang.String)
Async:
Async started = false
Async result = null
Resolved Exception:
Type = org.springframework.web.HttpMediaTypeNotAcceptableException
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 406
Error message = null
Headers = {Content-Type=[application/problem+json]}
Content type = application/problem+json
Body = {"type":"https://www.jhipster.tech/problem/problem-with-message","title":"Not Acceptable","status":406,"detail":"Could not find acceptable representation","path":"/api/download/DIRDIR/NAMENAME","message":"error.http.406"}
Forwarded URL = null
Redirected URL = null
Cookies = []
It looks like the request is sent with Accept: */*. What does Spring complain about then?
It could be an issue with your message converter, used in your test case. I too faced similar issue and resolved it by passing additional parameter in messageConverter for my mockMvc
this.restMockMvc = MockMvcBuilders.standaloneSetup(testResource)
.setCustomArgumentResolvers(pageableArgumentResolver)
.setControllerAdvice(exceptionTranslator)
.setMessageConverters(jacksonMessageConverter,new
ByteArrayHttpMessageConverter()).build();
You need to overload message converter property for MockMVC. for more info , relevant question
I was already using #SpringJUnitWebConfig(...) and included the #EnableWebMvc annotation to my imported Config. This seemed to add all the necessary converters. E.g.
#SpringJUnitWebConfig(MyTestConfig.class)
class MyTest {
#Inject
private WebApplicationContext wac;
private MockMvc mockMvc;
...
}
#EnableWebMvc
class MyTestConfig {
#Bean
...
}

Configuring custom Json Serializer for Spring controller test

I'm testing a controller:
#RestController()
public class MessagesController {
...
}
Using #WebMvcTest annotation:
#RunWith(SpringRunner.class)
#WebMvcTest(value = {MessagesController.class})
public class MessagesControllerTest {
private MockMvc mvc;
....
this.mvc.perform(
get("/messages/{id}", "dummyId")
.contentType(MediaType.APPLICATION_JSON))
.andDo(print())
.andExpect(status().isOk());
...
But when I launch my test Spring tries to serialize an object of type List> and it fails:
Resolved Exception:
Type = org.springframework.http.converter.HttpMessageNotWritableException
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 500
Error message = null
Headers = {Content-Type=[application/json;charset=UTF-8]}
Content type = application/json;charset=UTF-8
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
java.lang.AssertionError: Status
Expected :200
Actual :500
When I follow the execution in debug mode I found that the exception is thrown from : com.fasterxml.jackson.databind.ser.std.CollectionSerializer#serializeContents
And it's a JsonMappingException :
com.fasterxml.jackson.databind.JsonMappingException: Unwrapped property requires use of type information: can not serialize without disabling `SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS` (through reference chain: org.springframework.hateoas.Resource["content"]).
I also tried to inject an ObjectMapper into my context, but it's not used. Another ObjectMapper is used in the Serilaization process. This is the ObjectMapper I inject with #Import(HateoasConfiguration.class) on my test class:
#EnableHypermediaSupport(type = EnableHypermediaSupport.HypermediaType.HAL)
#Configuration
public class HateoasConfiguration
{
private static final String SPRING_HATEOAS_OBJECT_MAPPER = "_halObjectMapper";
#Autowired
#Qualifier(SPRING_HATEOAS_OBJECT_MAPPER)
private ObjectMapper springHateoasObjectMapper;
#Bean(name = "objectMapper")
public ObjectMapper objectMapper() {
springHateoasObjectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
springHateoasObjectMapper.disable(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS);
springHateoasObjectMapper.registerModules(
new ParameterNamesModule(),
new Jdk8Module(),
new JavaTimeModule(),
new URNModule()
);
return springHateoasObjectMapper;
}
}

Resources