0

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.

enter image description here

What I've tried so far:

  1. Set @RequestMapping to @RequestMapping(value = "/getValuesAsJson", method = RequestMethod.GET, produces = "text/javascript) -> Response Content-Type in browser turns to text/html

  2. Removed produces tag in RequestMapping entirely -> Response Content-Type in browser turns to application/xml;charset=UTF-8

  3. 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...

3
  • 1
    In your @RequestMapping annotation is written: produces = MediaType.APPLICATION_JSON_VALUE. MediaType.APPLICATION_JSON is a "public constant media type for application/json". So, it produces application/json. Did you try to remove or change it? Commented Dec 2, 2022 at 17:03
  • If i remove it, the content-type is application/xml;charset=UTF-8. if i set it to produces = "application/javascript", i receive content-type = text/html
    – d00d
    Commented Dec 3, 2022 at 8:11
  • Check this answer stackoverflow.com/a/21098951/460557 and please fix your application. "application/javascript" is considered obsolete for around 10 years now and officially considered so beginning of last year. So maybe the new version of Spring boot is ignoring it you should check mediatype for "text/javascript" instead Commented Dec 3, 2022 at 18:52

1 Answer 1

0

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.

Not the answer you're looking for? Browse other questions tagged or ask your own question.