Как разрешить исключение MethodArgumentConversionNotSupportedException с MockMvc?

Я пишу модульный тест для метода контроллера, который принимает MultipartFileи пользовательский объект MessageAttachment, До сих пор я вижу, что MultipartFile является правильным форматом для запроса, а MessageAttachment - нет.

Разбор messageAttachment выдает ошибку 500 на стороне сервера с MethodArgumentConversionNotSupportedException,

Кажется, что проблема с преобразованием MessageAttachment в MockMultipartFile в тесте. Это похоже на пример, показанный здесь - /questions/15590653/ispolzovanie-spring-mvc-test-dlya-modulnogo-testirovaniya-mnogochastnogo-post-zaprosa/15590659#15590659

Вопрос:

Как вы можете разрешить исключение MethodArgumentConversionNotSupportedException с MockMvc?

Тестируемый метод контроллера

 @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
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());

}

Консольный вывод 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 ответ

Решение

Вы хотите использовать @RequestPart вместо @RequestParam для части запроса, которая application/json, Javadoc для @RequestPart состояния

Поддерживаемые типы аргументов метода включают MultipartFile в сочетании с весны MultipartResolver абстракция, javax.servlet.http.Part в сочетании с многочастными запросами Servlet 3.0 или иным образом для любого другого аргумента метода, содержимое части передается через HttpMessageConverter принимая во внимание заголовок "Content-Type" части запроса. Это аналогично тому, что @RequestBody позволяет разрешить аргумент, основанный на содержимом регулярного запроса, не состоящего из нескольких частей.

Обратите внимание, что @RequestParam аннотацию также можно использовать для связывания части запроса "multipart / form-data" с аргументом метода, поддерживающим те же типы аргументов метода. Основное отличие состоит в том, что когда аргумент метода не является строкой, @RequestParam полагается на преобразование типа через зарегистрированный Converter или же PropertyEditor в то время как @RequestPart опирается на HttpMessageConverters принимая во внимание заголовок "Content-Type" части запроса. @RequestParam скорее всего будет использоваться с полями формы имя-значение, в то время как @RequestPart скорее всего будет использоваться с частями, содержащими более сложный контент (например, JSON, XML).

Предположительно, вы не зарегистрировали Converter ни PropertyEditor для анализа содержимого этой части, тогда как HttpMessageConverter для JSON автоматически регистрируется (в зависимости от вашей версии Spring MVC/Boot), если у вас есть Джексон на пути к классам.

Другие вопросы по тегам