Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HttpMediaTypeNotAcceptableException: Could not find acceptable representation in exceptionhandler

I have the following image download method in my controller (Spring 4.1):

@RequestMapping(value = "/get/image/{id}/{fileName}", method=RequestMethod.GET)
public @ResponseBody byte[] showImageOnId(@PathVariable("id") String id, @PathVariable("fileName") String fileName) {
    setContentType(fileName); //sets contenttype based on extention of file
    return getImage(id, fileName);
}

The following ControllerAdvice method should handle a non-existing file and return a json error response:

@ExceptionHandler(ResourceNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public @ResponseBody Map<String, String> handleResourceNotFoundException(ResourceNotFoundException e) {
    Map<String, String> errorMap = new HashMap<String, String>();
    errorMap.put("error", e.getMessage());
    return errorMap;
}

My JUnit test works flawless

(EDIT this is because of extention .bla : this also works on appserver):

@Test
public void testResourceNotFound() throws Exception {
    String fileName = "bla.bla";
      mvc.perform(MockMvcRequestBuilders.get("/get/image/bla/" + fileName)
            .with(httpBasic("test", "test")))
            .andDo(print())
            .andExpect(jsonPath("$error").value(Matchers.startsWith("Resource not found")))
            .andExpect(status().is(404));
}

and gives the following output:

MockHttpServletResponse:
          Status = 404
   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=[application/json]}
    Content type = application/json
            Body = {"error":"Resource not found: bla/bla.bla"}
   Forwarded URL = null
  Redirected URL = null
         Cookies = []

However on my appserver i get the following error message when trying to donwload non existing image:

(EDIT this is because of extention .jpg : this also fails on JUnit test with .jpg extention):

ERROR org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver - Failed to invoke @ExceptionHandler method: public java.util.Map<java.lang.String, java.lang.String> nl.krocket.ocr.web.controller.ExceptionController.handleResourceNotFoundException(nl.krocket.ocr.web.backing.ResourceNotFoundException) org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation

I have configured messageconverters in my mvc configuration as follows:

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    converters.add(mappingJackson2HttpMessageConverter());
    converters.add(byteArrayHttpMessageConverter());
}

@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
    //objectMapper.registerModule(new JSR310Module());
    MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
    converter.setObjectMapper(objectMapper);
    converter.setSupportedMediaTypes(getJsonMediaTypes());
    return converter;
}

@Bean
public ByteArrayHttpMessageConverter byteArrayHttpMessageConverter() {
    ByteArrayHttpMessageConverter arrayHttpMessageConverter = new ByteArrayHttpMessageConverter();
    arrayHttpMessageConverter.setSupportedMediaTypes(getImageMediaTypes());
    return arrayHttpMessageConverter;
}

What am i missing? And why is the JUnit test working?

like image 367
s.ijpma Avatar asked Sep 02 '15 10:09

s.ijpma


People also ask

How to handle error in Spring Boot?

Exception HandlerThe @ExceptionHandler is an annotation used to handle the specific exceptions and sending the custom responses to the client. Define a class that extends the RuntimeException class. You can define the @ExceptionHandler method to handle the exceptions as shown.


2 Answers

You need to decide how the media type of the response should be determined by Spring. That can be done in several ways:

  • path extension (eg. /image.jpg)
  • URL parameter (eg. ?format=jpg)
  • HTTP Accept header (eg. Accept: image/jpg)

By default, Spring looks at the extension rather than the Accept header. This behaviour can be changed if you implement a @Configuration class that extends WebMvcConfigurerAdapter (or since Spring 5.0 simply implement WebMvcConfigurer. There you can override configureContentNegotiation(ContentNegotiationConfigurer configurer) and configure the ContentNegotiationConfigurer to your needs, eg. by calling

ContentNegotiationConfigurer#favorParameter
ContentNegotiationConfigurer#favorPathExtension

If you set both to false, then Spring will look at the Accept header. Since your client can say Accept: image/*,application/json and handle both, Spring should be able to return either the image or the error JSON.

See this Spring tutorial on content negotiation for more information and examples.

like image 75
Adam Michalik Avatar answered Sep 25 '22 01:09

Adam Michalik


Pay attention to your HTTP Accept header. For example, if your controller produces "application/octet-stream" (in response), your Accept header should NOT be "application/json" (in request):

@GetMapping(value = "/download", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public void download(HttpServletResponse response) {}
like image 33
naXa Avatar answered Sep 26 '22 01:09

naXa