Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return literal JSON strings in spring mvc @ResponseBody

I am storing objects in my database as JSON strings. I want to make a REST service that exposes these strings. When I write my methods however, the strings I get back have their quotes escaped. For example, I have included a method that returns a String,

@RequestMapping(value = "test", method = RequestMethod.GET) public @ResponseBody String getTest() {     return "{\"a\":1, \"b\":\"foo\"}"; } 

but when I call this method in the browser I get a back "{\"a\":1, \"b\":\"foo\"}" when what I really want to happen is {"a": 1, "b": "foo"}. I think "String" as the return type is likely the problem, but what else can I do? A wrapper class does the same thing:

{   "value" : "{\"a\":1, \"b\":\"foo\"}" } 

I could serialize it and then return the object, but that seems a bit ridiculous. Here is a possibly the relevant portion of my configuration file:

@Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {     super.configureMessageConverters(converters);     converters.add(mappingJacksonHttpMessageConverter()); }  @Bean MappingJacksonHttpMessageConverter mappingJacksonHttpMessageConverter() {     MappingJacksonHttpMessageConverter mappingJacksonHttpMessageConverter = new MappingJacksonHttpMessageConverter();     ObjectMapper objectMapper = new ObjectMapper();     objectMapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);     mappingJacksonHttpMessageConverter.setObjectMapper(objectMapper);     mappingJacksonHttpMessageConverter.setPrettyPrint(true);     return mappingJacksonHttpMessageConverter; } 

Thanks

EDIT: as was suggested below, it seems the string is being double encoded. Commenting out the 2 classes in my configuration fixes this issue. However, I still have other places where I want to return Objects and would like to keep those running through that common serializing bean that I know where to configure. So I see my options as: a) Do all the serializing myself. All methods return Strings, and those that are already JSON return themselves, and those that are objects all return JSONUtil.toJson(object). I don't love this approach, but I know it will work. b) Use a wrapper class that looks kind of like:

public static class Wrapper {      @JsonRawValue     private final String value; } 

This leads to an awkward "value" at the front though that has no real meaning.

Basically what I want is @JsonRawValue, but to have it work on RequestMapping methods instead of properties. Thoughts? Opinions? Other suggestions?

like image 227
newmanne Avatar asked Mar 19 '13 18:03

newmanne


2 Answers

This works with Jackson 2 (at least):

@Controller public class YourController {      @RequestMapping(..)     public @ResponseBody Json get() {         return new Json("{ \"attr\" : \"value\" }");     } }  class Json {      private final String value;      public Json(String value) {         this.value = value;     }      @JsonValue     @JsonRawValue     public String value() {         return value;     } } 

Not particularly pretty but works. I only wish Spring supported this:

@RequestMapping(..) public @JsonRawValue @ResponseBody String get() {     // ... } 
like image 183
Jukka Avatar answered Oct 07 '22 12:10

Jukka


I guess what you want is producing a response with content-type application/json. In your case, when you have the json-data as a raw string, do the following:

In your controller add produces="application/json" to your @RequestMapping attribute:

@RequestMapping(value = "test", method = RequestMethod.GET, produces="application/json") public @ResponseBody String getTest() {     return "{\"a\":1, \"b\":\"foo\"}"; } 

Then you have to configure the StringHttpMessageConverter to accept the application/json media-type.

With Java-config:

@Override public void configureMessageConverters(         List<HttpMessageConverter<?>> converters) {     StringHttpMessageConverter stringConverter = new StringHttpMessageConverter(             Charset.forName("UTF-8"));     stringConverter.setSupportedMediaTypes(Arrays.asList( //             MediaType.TEXT_PLAIN, //             MediaType.TEXT_HTML, //             MediaType.APPLICATION_JSON));     converters.add(stringConverter); } 

With XML-config:

<bean class = "org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">     <property name="messageConverters">         <array>             <bean class = "org.springframework.http.converter.StringHttpMessageConverter">                 <property name="supportedMediaTypes" value="application/json; charset=UTF-8" />             </bean>         </array>     </property> </bean> 
like image 43
Florian Fankhauser Avatar answered Oct 07 '22 11:10

Florian Fankhauser