I just announced the new Spring 5 modules in REST With Spring:

>> CHECK OUT THE COURSE

1. Overview

If you’ve been developing anything on the web, you’re aware of the same-origin policy constraint browsers have when dealing with AJAX requests. The simple overview of the constraint is that any request originating from a different domain, schema or port, will not be permitted.

One way to relax this browser restriction when working with JSON data – is by using JSON with padding (JSON-P).

This article discusses Spring’s support for working with JSON-P data – with the help of AbstractJsonpResponseBodyAdvice.

2. JSON-P in Action

The same-origin policy is not imposed over the <script> tag, allowing scripts to be loaded across different domains. JSON-P technique takes advantage of this by passing the JSON response as the argument of the javascript function.

2.1. Preparation

In our examples, we will use this simple Company class:

public class Company {
 
    private long id;
    private String name;
 
    // standard setters and getters
}

This class will bind the request parameters and shall be returned from the server as JSON representation.

The Controller method is a simple implementation as well – returning the Company instance:

@RestController
public class CompanyController {

    @RequestMapping(value = "/companyRest",
      produces = MediaType.APPLICATION_JSON_VALUE)
    public Company getCompanyRest() {
        Company company = new Company(1, "Xpto");
        return company;
    }
}

On the client side we can use jQuery library to create and send an AJAX request:

$.ajax({
    url: 'http://localhost:8080/spring-mvc-java/companyRest',
    data: {
        format: 'json'
    },
    type: 'GET',
    ...
});

Consider an AJAX request against the following URL:

http://localhost:8080/spring-mvc-java/companyRest

The response from the server would be the following:

{"id":1,"name":"Xpto"}

As the request was sent against the same schema, domain, and port, the response will not get blocked, and JSON data will be allowed by the browser.

2.2. Cross-Origin Request

By changing the request URL to:

http://127.0.0.1:8080/spring-mvc-java/companyRest

the response will get blocked by the browser, due to request being sent from localhost to 127.0.0.1 which is considered a different domain and presents a violation of the same-origin policy.

With JSON-P, we are able to add a callback parameter to the request:

http://127.1.1.1:8080/spring-mvc-java/companyRest?callback=getCompanyData

On the client side it’s as easy as adding the following parameters to the AJAX request:

$.ajax({
    ...
    jsonpCallback:'getCompanyData',
    dataType: 'jsonp',
    ...
});

The getCompanyData will be the function called when the response is received.

If the server formats the response like the following:

getCompanyData({"id":1,"name":"Xpto"});

browsers will not block it, as it will treat the response as a script negotiated and agreed upon between the client and the server on account of matching getCompanyData in both request and the response.

3. @ControllerAdvice Annotation

The beans annotated with @ControllerAdvice are able to assist all or a specific subset of Controllers and is used to encapsulate cross-cutting behavior shared between different Controllers. Typical usage patterns are related to exception handling, adding attributes to models or registering binders.

Starting with Spring 4.1, @ControllerAdvice is able to register the implementations of ResponseBodyAdvice interface which allows changing the response after its being returned by a controller method but before being written by a suitable converter.

4. Changing the Response Using AbstractJsonpResponseBodyAdvice

Also starting with Spring 4.1, we now have access to the AbstractJsonpResponseBodyAdvice class – which formats the response according to JSON-P standards.

This section explains how to put the base class at play and change the response without making any changes to the existing Controllers.

In order to enable Spring support for JSON-P, let’s start with the configuration:

@ControllerAdvice
public class JsonpControllerAdvice 
  extends AbstractJsonpResponseBodyAdvice {

    public JsonpControllerAdvice() {
        super("callback");
    }
}

The support is made using the AbstractJsonpResponseBodyAdvice class. The key passed on the super method is the one that will be used in URL requesting JSON-P data.

With this controller advice, we automatically convert the response to JSON-P.

5. JSON-P with Spring in Practice

With the previously discussed configuration in place, we are able to make our REST applications respond with JSON-P. In the following example, we will return company’s data, so our AJAX request URL should be something like this:

http://127.0.0.1:8080/spring-mvc-java/companyRest?callback=getCompanyData

As a result of the previous configuration, the response will look as follows:

getCompanyData({"id":1,"name":"Xpto"});

As discussed, the response in this format will not get blocked despite originating from a different domain.

The JsonpControllerAdvice can easily be applied to any method that returns a response annotated with @ResponseBody and ResponseEntity.

There should be a function with the same name passed in the callback, getCompanyData, for handling all the responds.

6. Conclusion

This quick article shows how an otherwise tedious work of formatting the response to take advantage of JSON-P is simplified using the new functionality in Spring 4.1.

The implementation of the examples and code snippets can be found in this GitHub project.

I just announced the new Spring 5 modules in REST With Spring:

>> CHECK OUT THE LESSONS