问题
For some reason, my Spring controller is returning different responses if I access it via a browser or via my MockMVC test class. Could someone help me spot why?
First the controller method:
@RequestMapping(value = APPLICATIONS_ROOT, method = GET)
public HttpEntity<ApplicationsListResource> listApplications(@PageableDefault(page = DEFAULT_START,
size = DEFAULT_HITS_PER_PAGE) Pageable pageable) {
Page<Application> applications = applicationRepository.findAll(pageable);
ApplicationsListResource applicationListResource = new ApplicationsListResource(applications, pageable);
return new ResponseEntity<ApplicationsListResource>(applicationListResource, HttpStatus.OK);
}
Obviously there's a few unknown classes in there. ApplicationListResource
extends ResourceSupport
and contains a list of ApplicationResource
called applications
. This ApplicationResource
also extends ResourceSupport
.
When I access the code via the browser, I'll get something along the lines of:
{
"_links": {
"self": {
"href": "http://localhost:10000/applications{?page,size,sort}",
"templated": true
}
},
"_embedded": {
"applications": [{
"displayname": "One",
"description": "My Test Application!",
"locations": ["http://foo.com"],
"_links": {
"self": { "href": "http://localhost:10000/applications/one" }
}
}, {
...
}]
},
"page": {
"size": 20,
"totalElements": 7,
"totalPages": 1,
"number": 0
}
}
Looks HATEOAS compliant to me. But when I go via a MockMVC request...
getMockMvc().perform(get(APPLICATIONS_ROOT)).andExpect(status().isOk()).andExpect(content().contentType(MediaTypes.HAL_JSON)).andExpect(jsonPath("$._embedded.applcations", hasSize(5))).andReturn();
The responses have no HATEOAS compliant elements in them so my tests fail on the jsonPath check:
{
"page" : 0,
"size" : 10,
"sort" : null,
"total" : 5,
"applications" : [ {
"name" : "one",
"version" : "1.0",
...
I've tried changing the ContentType on the GET request for the MockMVC method but it makes no difference. In the browser, I'm not setting any specific content type, headers etc.
I know the MockMVC class makes it HTTP requests with certain differences from the usual RestTemplate so perhaps it's something like this? Can anyone see anything obvious I am missing?
I will add additional code if needs be but it would have made the question even more long winded than it is currently.
回答1:
Spring HATEOAS adds additional configuration for rendering hal properly, check this for details: http://docs.spring.io/spring-hateoas/docs/0.19.0.RELEASE/reference/html/#configuration.
In a nutshell it adds proper MixIn
s added by Jackson2HalModule
and HalHandlerInstantiator
to the ObjectMapper
. It's all configured in HypermediaSupportBeanDefinitionRegistrar.java
(https://github.com/spring-projects/spring-hateoas/blob/master/src/main/java/org/springframework/hateoas/config/HypermediaSupportBeanDefinitionRegistrar.java)
If you're using standalone mockMvc configuration you have to configure the ObjectMapper
manually to mimic spring's behaviour. I ran into same problem and ended up adding following configuration to my tests:
mockMvc = MockMvcBuilders.standaloneSetup(controller)
.setMessageConverters(
new MappingJackson2HttpMessageConverter(configureObjectMapper()))
.build();
and
private ObjectMapper configureObjectMapper() {
return Jackson2ObjectMapperBuilder.json()
.modules(new Jackson2HalModule())
.handlerInstantiator(new Jackson2HalModule.HalHandlerInstantiator(
new DelegatingRelProvider(
OrderAwarePluginRegistry.create(Arrays.asList(
new EvoInflectorRelProvider(),
new AnnotationRelProvider()))),
null))
.build();
}
来源:https://stackoverflow.com/questions/33127031/springs-mockmvc-responses-dont-match-browser-response