I'm experimenting with the new Spring 4.0 @RestController to return a simple text response from a controller:
@RestController
@RequestMapping(value = "/heartbeat")
public class HeartbeatController {
private static final Logger logger = LoggerFactory.getLogger(HeartbeatController.class);
@RequestMapping
public String heartbeat() {
logger.info("Received heartbeat!");
return "I'm Alive!";
}
@RequestMapping(value = "/test", produces = MediaType.TEXT_PLAIN_VALUE)
public String heartbeat2() {
logger.info("Received heartbeat!");
return "I'm Alive!";
}
}
When I access /heartbeat then I get back:
"I'm Alive!"
The result includes the double quotes, what I did not expect.
When I access /heartbeat/test then I get a empty response back, but I expect the I'm Alive! text.
UPDATE
curl -i http://myserver.com/rest/heartbeat
HTTP/1.1 200 OK Content-Type: application/json;charset=UTF-8 Server: Development/1.0 Date: Tue, 17 Dec 2013 18:59:08 GMT Cache-Control: no-cache Expires: Fri, 01 Jan 1990 00:00:00 GMT Content-Length: 12
"I'm Alive!"
curl -i -H "Accept: application/json" http://myserver.com/rest/heartbeat HTTP/1.1 200 OK Content-Type: application/json;charset=UTF-8 Server: Development/1.0 Date: Tue, 17 Dec 2013 19:01:12 GMT Cache-Control: no-cache Expires: Fri, 01 Jan 1990 00:00:00 GMT Content-Length: 12
"I'm Alive!"
curl -i http://myserver.com/rest/heartbeat/test
HTTP/1.1 406 Not Acceptable Server: Development/1.0 Date: Tue, 17 Dec 2013 19:00:13 GMT Cache-Control: no-cache Expires: Fri, 01 Jan 1990 00:00:00 GMT Content-Length: 0
curl -i -H "Accept: text/plain" http://myserver.com/rest/heartbeat/test
HTTP/1.1 406 Not Acceptable Server: Development/1.0 Date: Tue, 17 Dec 2013 19:02:06 GMT Cache-Control: no-cache Expires: Fri, 01 Jan 1990 00:00:00 GMT Content-Length: 0
I found out I was missing the StringHttpMessageConverter in my WebConfig's configureMessageConverters. I was configuring the message converters to control the Jackson ObjectMapper.
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
mappingJackson2HttpMessageConverter.setPrettyPrint(SystemProperty.environment.value() == Development);
mappingJackson2HttpMessageConverter.setObjectMapper(objectMapper());
converters.add(mappingJackson2HttpMessageConverter);
converters.add(new StringHttpMessageConverter()); // THIS WAS MISSING
}
@RestController is a convenience annotation that means you no longer need to specify @ResponseBody annotation on your methods.
But it will mean that your response type is being defaulted to JSON and therefore wrapped in quotes to be properly formed.
@RestController
combines @Controller
and @ResponseBody
on your Controller class, as stated in the documentation.
When you annotate a method/a controller with @ResponseBody
, Spring assists you with content negotiation, using the Accept
HTTP request header and the produces
attribute on your annotation.
In your case:
application/json
response for your heartbeat action, because your HTTP client probably asks for that Content-Type and Spring did the content negotiation.text/plain
as a produces Content-Type on your Controller, whereas your HTTP client probably lists only application/json
in its Accept
request header.Update: I've used the exact same curl requests but don't get the same results. Maybe a Filter or a HTTP proxy-cache is modifying HTTP headers?
Default format is text/plain:
➜ curl -v http://localhost:8080/heartbeat
> GET /heartbeat HTTP/1.1
> User-Agent: curl/7.30.0
> Host: localhost:8080
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
< Content-Type: text/plain;charset=ISO-8859-1
< Content-Length: 13
< Date: Wed, 18 Dec 2013 13:34:12 GMT
<
Hello, World!%
And with a produces text/plain
attribute:
➜ curl -H "Accept: text/plain" -v http://localhost:8080/heartbeat/test
> GET /heartbeat/test HTTP/1.1
> User-Agent: curl/7.30.0
> Host: localhost:8080
> Accept: text/plain
>
< HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
< Content-Type: text/plain
< Content-Length: 13
< Date: Wed, 18 Dec 2013 13:39:07 GMT
<
Hello, World!%
This sample application does the same thing and get good results.
This solution worked for me. Please check the followings.
Fix the RequesMapping Annotation:
@RequestMapping(value = "/test", consumes = "*/*")
Check you have <mvc:annotation-driven />
directive
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With