问题
I'm writing a unit test for a controller method that accepts a MultipartFile
and a custom object MessageAttachment. So far I can see that the MultipartFile is the correct format for the request but the MessageAttachment is not.
The parsing of the messageAttachment throws a server side 500 error with MethodArgumentConversionNotSupportedException.
It seem to be an issue with converting the MessageAttachment to a MockMultipartFile in the test. This is similar to the example shown here - https://stackoverflow.com/a/21805186
Question:
How can you resolve a MethodArgumentConversionNotSupportedException with MockMvc?
Controller method under test
@RequestMapping(value = "/", method = RequestMethod.POST, consumes = "multipart/form-data", produces = "application/json")
public ResponseEntity<MessageAttachment> handleFileUpload(@RequestParam(value = "file", required = true) MultipartFile file, @RequestParam(value = "messageAttachment") MessageAttachment messageAttachment) {
//do stuff with the file and attachment passed in..
MessageAttachment attachment = new MessageAttachment();
return ResponseEntity.accepted().header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"" + file.getOriginalFilename() + "\"").body(attachment);
}
MockMvc Test
@Test
public void shouldSaveUploadedFile() throws Exception {
// Given
ObjectMapper mapper = new ObjectMapper();
MessageAttachment messageAttachment = new MessageAttachment();
messageAttachment.setTimestamp(new Date());
MockMultipartFile multipartFile = new MockMultipartFile("file", "test.txt", "text/plain",
"Spring Framework".getBytes());
//Mapping the msgAttachment to a MockMultipartFile HERE
MockMultipartFile msgAttachment = new MockMultipartFile("messageAttachment", "","application/json",
mapper.writeValueAsString(messageAttachment).getBytes());
// When
this.mockMvc.perform(MockMvcRequestBuilders.multipart("/media/")
.file(multipartFile)
.file(msgAttachment)).andDo(MockMvcResultHandlers.print());
}
Console output of MockMvcResultHandlers.print()
MockHttpServletRequest:
HTTP Method = POST
Request URI = /media/
Parameters = {}
Headers = {Content-Type=[multipart/form-data]}
Body = <no character encoding set>
Session Attrs = {}
Handler:
Type = com.fizz.buzz.fizzapi.controller.MediaUploadController
Method = public org.springframework.http.ResponseEntity<com.fizz.buzz.fizzapi.model.MessageAttachment> com.fizz.buzz.fizzapi.controller.MediaUploadController.handleFileUpload(org.springframework.web.multipart.Mu
ltipartFile,com.fizz.buzz.fizzapi.model.MessageAttachment,javax.servlet.http.HttpServletRequest)
Async:
Async started = false
Async result = null
Resolved Exception:
Type = org.springframework.web.method.annotation.MethodArgumentConversionNotSupportedException
ModelAndView:
View name = null
View = null
Model = null
回答1:
You'll want to use @RequestPart instead of @RequestParam for the part of the request that is application/json. The javadoc for @RequestPart states
Supported method argument types include
MultipartFilein conjunction with Spring'sMultipartResolverabstraction,javax.servlet.http.Partin conjunction with Servlet 3.0 multipart requests, or otherwise for any other method argument, the content of the part is passed through anHttpMessageConvertertaking into consideration the 'Content-Type' header of the request part. This is analogous to what@RequestBodydoes to resolve an argument based on the content of a non-multipart regular request.Note that
@RequestParamannotation can also be used to associate the part of a "multipart/form-data" request with a method argument supporting the same method argument types. The main difference is that when the method argument is not a String,@RequestParamrelies on type conversion via a registeredConverterorPropertyEditorwhile@RequestPartrelies onHttpMessageConverterstaking into consideration the 'Content-Type' header of the request part.@RequestParamis likely to be used with name-value form fields while@RequestPartis likely to be used with parts containing more complex content (e.g. JSON, XML).
Presumably, you haven't registered a Converter, nor a PropertyEditor, to parse the content of that part, whereas an HttpMessageConverter for JSON is automatically registered (depending on your Spring MVC/Boot version) if you have Jackson on the classpath.
来源:https://stackoverflow.com/questions/50953227/how-to-resolve-methodargumentconversionnotsupportedexception-with-mockmvc