I have this method:
@RequestMapping(value = "/getValuesAsJson", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public ValuesJsonObject getValuesAsJson(@RequestParam final String ownerId, @RequestParam final String searchString, @RequestParam final Long valueTypeId,
@RequestParam(required = false) final boolean extendedSearch, @RequestParam(required = false) final String meta3Filter,
@RequestParam(required = false) final String meta4Filter, @RequestParam(required = false) final String valueFilter,
@RequestParam(required = false) final String searchFields, @RequestParam(required = false) final Boolean distinct) {
//...Some Code
final ValuesJsonObject valuesObject = new ValuesJsonObject();
valuesObject.setValues(values);
return valuesObject;
}
This method is used to fetch data that is used for a GWT select box. The response normally looks something like this:
/**/gwt_jsonp.P0.onSuccess({"values":[{"denotation":"ZFO - Franconia","value":"ZFO - Franconia","description":null,"meta1":null,"meta3":null,"meta4":null}]});
It's some kind of GWT callback thing where JSON data is inside this Javascript function.
The response content-type was application/javascript
in Spring 4.3 environment. Now, after the upgrade, the response-type is application/json. I tried to create a header and manually set up a ResponseEntity with a header that has Content-Type = "application/javascript" but still application/json is returned.
What I've tried so far:
Set @RequestMapping to
@RequestMapping(value = "/getValuesAsJson", method = RequestMethod.GET, produces = "text/javascript)
-> Response Content-Type in browser turns totext/html
Removed produces tag in RequestMapping entirely -> Response Content-Type in browser turns to
application/xml;charset=UTF-8
Tried to manually set the Response headers like that, but that got me a 500 error:
HttpHeaders headers = new HttpHeaders(); headers.add(HttpHeaders.CONTENT_TYPE, "text/javascript"); return new ResponseEntity<>(valuesObject, headers, HttpStatus.OK);
Edit: Some new findings! When I remove the data from the body and just ad null, then the content-type is set properly. If I have the data in the body, I receive a 500 error. It must have something to do with the payload (but it worked before the Spring update....).
What I then tried was to properly transform the payload into JSON data using ObjectMapper. The response data then looks like normal JSON and the content-type is correctly set to application/javascript:
Response:
{"values":[{"denotation":"ZFO - Franconia","value":"ZFO - Franconia","description":null,"meta1":null,"meta3":null,"meta4":null}]}
BUT the Javascript callback is missing in this response. Question is how to add this back again. I think that's a GWT issue...
CodePudding user response:
I have a solution for my problem.
When we upgraded to Spring 5.6, Spring's AbstractJsonpResponseBodyAdvice was removed. I think this extension class was responsible for setting the correct content-type in our response and converting everything to JSONP. When the class was gone, the wrong content-type was set. So I had to manually set content-type to text/javascript in @RequestMapping, but I also had to provide it in the header of the response.
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_TYPE, "text/javascript");
I also had to capture the callback address of the JSONP / GWT call in a new parameter in method signature
@RequestMapping(value = "/getValuesAsJson", method = RequestMethod.GET, produces = "text/javascript")
public ResponseEntity getValuesAsJson(@RequestParam final String ownerId, @RequestParam final String searchString, @RequestParam final Long valueTypeId,
@RequestParam(required = false) final boolean extendedSearch, @RequestParam(required = false) final String meta3Filter,
@RequestParam(required = false) final String meta4Filter, @RequestParam(required = false) final String valueFilter,
@RequestParam(required = false) final String searchFields, @RequestParam(required = false) final Boolean distinct,
@RequestParam(required = true) final String callback) {
And finally I wrapped the Javascript method name around the JSON data:
return ResponseEntity.ok()
.headers(headers)
.body(callback "(" valuesObjectAsJson ")");
This was basically the solution someone else here on SA proposed but I can't find the thread again.