'Unable to get different Content-Types in request mapping using Spring Framework

Here is my controller class:

@Controller
@RequestMapping("/actuator")
public class HealthController {

    @RequestMapping(value = "/metrics", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON)
    @ResponseBody
    public HealthModel getDump() throws JsonProcessingException {
        return new HealthModel();
        //return mapper.writeValueAsString(metrics.invoke());
    }

    @RequestMapping(value = "/metrics", method = RequestMethod.GET, produces = MediaType.TEXT_PLAIN)
    @ResponseBody
    public String getHealth() {
        return "HEALTHY";
    }
}

Model:

public class HealthModel {

    @JsonProperty
    private String status;
    @JsonProperty
    private int id;

    public HealthModel(){
        this.status="WARN";
        this.id=2;
    }

}

Note I have mapped /metrics to return json or plain-text depending on the Accept Header in the request

When I make request at

curl -v -H "Accept: application/json" http://localhost:8080/myapp/actuator/metrics

I get expected response in json {"status":"WARN","id":2}.

However, when I try

curl -v -H "Accept: text/plain" http://localhost:8080/myapp/actuator/metrics

I get HTTP/1.1 406 Not Acceptable.


EDIT

@EnableWebMvc
@Configuration
public class AppMvcConfig extends WebMvcConfigurerAdapter {

   @Resource(name = "appObjectMapper")
    private ObjectMapper appObjectMapper;

    @Resource(name = "modelObjectMapper")
    private ObjectMapper modelObjectMapper;

 @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
       
        final MappingJackson2HttpMessageConverter inputConverter = new MappingJackson2HttpMessageConverter();
        inputConverter.setObjectMapper(appObjectMapper);

        final MappingJackson2HttpMessageConverter outputConverter = new MappingJackson2HttpMessageConverter();
        outputConverter.setObjectMapper(modelObjectMapper);

        converters.add(new JacksonDualMapperConverter(appObjectMapper, modelObjectMapper));

        super.configureMessageConverters(converters);
    }

}


Solution 1:[1]

Since you're adding a custom MessageConverter configureMessageConverters, this turns off default converter registration (see JavaDoc).

So when content negotiation kicks in, you only have one message converter (the Jackson one) that only supports JSON media types and does not know how to handle text/plain.

You should add a StringHttpMessageConverter to the list in order to support text/plain.

converters.add(new StringHttpMessageConverter());

Solution 2:[2]

Just in case anyone still gets the Type mismatch: cannot convert from MediaType to String[] error:

The solution is to use MediaType.APPLICATION_JSON_VALUE

instead of MediaType.APPLICATION_JSON

Regards

Solution 3:[3]

According to the documentation, @ResponseBody indicates that indicates that the return type should be written straight to the HTTP response body (and not placed in a Model, or interpreted as a view name). So annotation should be there. On the second look, your produces annotation does not seem to be correct. It should be produces = MediaType.TEXT_PLAIN_VALUE and not produces = MediaType.TEXT_PLAIN. I tried the following and it worked for me:

    @RequestMapping(value = "/metrics", method = RequestMethod.GET, produces = MediaType.TEXT_PLAIN_VALUE)
    @ResponseBody
    public String getHealth() {
        return "HEALTHY";
    }

You also might have to add StringHttpMessageConverter.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Camilo
Solution 3