45

I have a method in my controller that should returns a String in JSON. It returns JSON for non primitive types:

@RequestMapping(value = "so", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
ResponseEntity<String> so() {
    return new ResponseEntity<String>("This is a String", HttpStatus.OK);
}

The curl response is:

This is a String
Sydney
  • 11,964
  • 19
  • 90
  • 142

4 Answers4

73

The root of the problem is that Spring (via ResponseEntity, RestController, and/or ResponseBody) will use the contents of the string as the raw response value, rather than treating the string as JSON value to be encoded. This is true even when the controller method uses produces = MediaType.APPLICATION_JSON_VALUE, as in the question here.

It's essentially like the difference between the following:

// yields: This is a String
System.out.println("This is a String");

// yields: "This is a String"
System.out.println("\"This is a String\"");

The first output cannot be parsed as JSON, but the second output can.

Something like '"'+myString+'"' is probably not a good idea however, as that won't handle proper escaping of double-quotes within the string and will not produce valid JSON for any such string.

One way to handle this would be to embed your string inside an object or list, so that you're not passing a raw string to Spring. However, that changes the format of your output, and really there's no good reason not to be able to return a properly-encoded JSON string if that's what you want to do. If that's what you want, the best way to handle it is via a JSON formatter such as Json or Google Gson. Here's how it might look with Gson:

import com.google.gson.Gson;

@RestController
public class MyController

    private static final Gson gson = new Gson();

    @RequestMapping(value = "so", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    ResponseEntity<String> so() {
        return ResponseEntity.ok(gson.toJson("This is a String"));
    }
}
zacronos
  • 1,487
  • 1
  • 12
  • 13
  • 7
    This is the correct answer. You should probably ask yourself if you really need to support JSON for this endpoint that will only return a string. If not just change the produces to text/plain. – CaptRespect May 17 '17 at 15:56
  • 3
    Should be accepted as right answer rather than previous – Dmytro Kryvenko Oct 20 '17 at 07:29
24
@RequestMapping(value = "so", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public @ResponseBody String so() {
    return "This is a String";
}
NimChimpsky
  • 46,453
  • 60
  • 198
  • 311
  • that most definitely does work ... what do you get as a reponse, and what exactly do you require ? – NimChimpsky Aug 22 '13 at 17:03
  • I get `This is a String` and if I return an object I get `{"repeatSecond":15}`. So for primitive, it seems that I don't get a JSON string, but for object I do. – Sydney Aug 22 '13 at 19:33
  • BTW I found a related post you answered: http://stackoverflow.com/questions/12911069/spring-responsebody-produces-an-invalid-json-for-primitive-types – Sydney Aug 22 '13 at 20:02
4
import org.springframework.boot.configurationprocessor.json.JSONException;
import org.springframework.boot.configurationprocessor.json.JSONObject;

public ResponseEntity<?> ApiCall(@PathVariable(name = "id") long id) throws JSONException {
    JSONObject resp = new JSONObject();
    resp.put("status", 0);
    resp.put("id", id);

    return new ResponseEntity<String>(resp.toString(), HttpStatus.CREATED);
}
Suzana
  • 4,251
  • 2
  • 28
  • 52
user2308728
  • 91
  • 1
  • 2
1

An alternative solution is to use a wrapper for the String, for instances this:

public class StringResponse {
    private String response;
    public StringResponse(String response) {
        this.response = response;
    }
    public String getResponse() {
        return response;
    }
}

Then return this in your controller's methods:

ResponseEntity<StringResponse>
Enrico Giurin
  • 2,183
  • 32
  • 30