Jackson Top

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE

1. Overview

In this short tutorial, we're going to take a close look at how to work with JSON parameters in Spring MVC.

First, we'll start with a little bit of background on JSON parameters. Then, we'll go down the rabbit hole to see how to send JSON parameters in POST and GET requests.

2. JSON Parameters in Spring MVC

Using JSON to send or receive data is a common practice among web developers. The hierarchical structure of the JSON strings offers a more compact and human-readable way to represent HTTP request parameters.

By default, Spring MVC provides out-of-the-box data binding for simple data types such as String. For that purpose, it uses a list of built-in property editors under-the-hood.

However, in real-world projects, we may want to bind more complex data types. For example, it might be handy to be able to map a JSON parameter into a model object.

3. Send JSON Data in POST

Spring provides a straightforward way to send JSON data via POST requests. The built-in @RequestBody annotation can automatically deserialize the JSON data encapsulated in the request body into a particular model object.

In general, we don't have to parse the request body ourselves. We can use the Jackson library to do all the heavy lifting for us.

Now, let's see how to send JSON data via a POST request in Spring MVC.

Firstly, we need to create a model object to represent the passed JSON data. For instance, consider the Product class:

public class Product {

    private int id;
    private String name;
    private double price;

    // default constructor + getters + setters

}

Secondarily, let's define a Spring handler method that accepts POST requests:

@PostMapping("/create")
@ResponseBody
public Product createProduct(@RequestBody Product product) {
    // custom logic
    return product;
}

As we can see, annotating the product argument with @RequestBody is enough to bind the JSON data sent from the clients.

Now, we can test our POST request using cURL:

curl -i \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-X POST --data \
  '{"id": 1,"name": "Asus Zenbook","price": 800}' "http://localhost:8080/spring-mvc-basics-4/products/create"

4. Send JSON Parameter in GET

Spring MVC offers @RequestParam to extract query parameters from GET requests. However, unlike @RequestBody, the @RequestParam annotation supports only simple data types such as int and String.

So, to send JSON, we'll need to define our JSON parameter as a simple string.

The big question here is: How do we convert our JSON parameter (which is a String) into an object of the Product class?

The answer is pretty simple! The ObjectMapper class provided by the Jackson library offers a flexible way to convert JSON strings into Java objects.

Now, let's see how to send a JSON parameter via a GET request in Spring MVC. First, we'll need to create another handler method in our controller to handle GET requests:

@GetMapping("/get")
@ResponseBody
public Product getProduct(@RequestParam String product) throws JsonMappingException, JsonProcessingException {
    Product prod = objectMapper.readValue(product, Product.class);
    return prod;
}

As shown above, the readValue() method allows deserializing the JSON parameter product directly into an instance of the Product class.

Note that we define our JSON query parameter as a String object. Now, what if we want to pass a Product object like we did when using @RequestBody?

To answer this question, Spring provides a concise and flexible solution through custom property editors.

First, we'll need to create a custom property editor to encapsulate the logic of converting the JSON parameter given as a String to a Product object:

public class ProductEditor extends PropertyEditorSupport {

    private ObjectMapper objectMapper;

    public ProductEditor(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        if (StringUtils.isEmpty(text)) {
            setValue(null);
        } else {
            Product prod = new Product();
            try {
                prod = objectMapper.readValue(text, Product.class);
            } catch (JsonProcessingException e) {
                throw new IllegalArgumentException(e);
            }
            setValue(prod);
        }
    }

}

Next, let's bind the JSON parameter to an object of Product class:

@GetMapping("/get2")
@ResponseBody
public Product get2Product(@RequestParam Product product) {
    // custom logic
    return product;
}

Lastly, we need to add the last missing piece of the puzzle. Let's register ProductEditor in our Spring controller:

@InitBinder
public void initBinder(WebDataBinder binder) {
    binder.registerCustomEditor(Product.class, new ProductEditor(objectMapper));
}

Bear in mind that we need to URL-encode the JSON parameter to ensure safe transport.

So, instead of:

GET /spring-mvc-basics-4/products/get2?product={"id": 1,"name": "Asus Zenbook","price": 800}

We need to send:

GET /spring-mvc-basics-4/products/get2?product=%7B%22id%22%3A%201%2C%22name%22%3A%20%22Asus%20Zenbook%22%2C%22price%22%3A%20800%7D

5. Conclusion

To sum it up, we saw how to work with JSON in Spring MVC. Along the way, we showcased how to send JSON parameters in POST and GET requests.

As always, the full source code of the examples is available over on GitHub.

Jackson bottom

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE
Comments are closed on this article!