The @RequestBody Annotation

The @RequestBody Annotation

1 Comment

Last Updated on September 6, 2021 by jt

Spring Web applications and services need to process client requests sent over HTTP. When the HTTP clients send data with the request, the data is in the request body. On the application side, you need a mechanism to deserialize data sent in the request body to domain objects. This is done using the @RequestBody annotation.

In this post, I will explain how to use the @RequestBody annotation.

Deserializing RequestBody to Domain Object using @RequestBody annotation

The @RequestBody annotation is applicable to handler methods of Spring controllers. This annotation indicates that Spring should deserialize a request body into an object. This object is passed as a handler method parameter.

Under the hood, the actual deserialization is done by one of the many implementations of MessageConverter.

To understand how this works, let’s create a simple domain class to represent user credentials.

The code of the User domain class is this.

User.java

package gur.springframework.model;

public class User {
private String userName;
private String password;

    public User() {
    }

    public User(String userName, String password) {
        this.userName = userName;
        this.password = password;
    }
   //Getter and Setter

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getUserName() {
        return userName;
    }

    public String getPassword() {
        return password;
    }
}

The code of the controller is this.

DemoController.java

package gur.springframework.controller;

import gur.springframework.model.User;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

@RequestMapping("api/v1")
@RestController
public class DemoController {

    @PostMapping("users")
    @ResponseStatus(HttpStatus.CREATED)
    public User registerUserCredential(@RequestBody User user){
        System.out.println("User ID: "+user.getUserName());
        System.out.println("User ID: "+user.getPassword());
        return user;
    }
}

In the preceding controller class, the @RequestBody annotation is specified on the registerUserCredential() method. This annotation informs Spring to deserialize an incoming request body to the User domain object. The System.out.println statements prints to console the user name and password of the deserialised User object.

You can send a POST request to invoke the registerUserCredential() handler with the following URL:

http://localhost:8080/api/v1/users

This figure shows a POST request sent from Postman.

Post request with request body

After sending the request, examine the console log. This figure shows the fields of the deserialized User object.

Fields of Deserialized Domain Object

The automated unit test code of the controller class is this.

DemoControllerTest.java

package gur.springframework.controller;


import com.fasterxml.jackson.databind.ObjectMapper;
import gur.springframework.model.User;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@ExtendWith(MockitoExtension.class)
class DemoControllerTest {

  private  MockMvc mockMvc;
  private User user;

    @BeforeEach
    void setUp() {
        user = new User("John","pass1234");

         mockMvc = MockMvcBuilders
                .standaloneSetup(DemoController.class)
                .build();
    }

@Test
    void registerUserCredential()throws Exception {

    MvcResult result =    mockMvc.perform(post("/api/v1/users")
            .contentType(MediaType.APPLICATION_JSON_VALUE)
            .content(asJsonString(user)))
            .andExpect(status().isCreated())
            .andReturn();
    String content = result.getResponse().getContentAsString();
    System.out.println(content);

}
    public static String asJsonString(final Object obj) {
        try {
            return new ObjectMapper().writeValueAsString(obj);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

Deserializing RequestBody to Map using @RequestBody annotation

You can also use the @RequestBody annotation to deserialize a request body to a Java Map.

As a programmer, you don’t need to do anything special. You only need to pass a Map parameter to the handler method. It is @RequestBody along with HttpMessageConverter who will deserialize the JSON in the request body to the Map.

The code is this.

@PostMapping("/map/users")
@ResponseStatus(HttpStatus.CREATED)
public Map<String, String> registerUserCredentialThroughMap(@RequestBody Map<String, String> userMap){
    System.out.println("User ID: "+userMap.get("userName"));
    System.out.println("User ID: "+userMap.get("password"));
    return userMap;
}

Once you run the application, access it using this URL from Postman.

http://localhost:8080/api/v1/map/users

As a result, you can see the deserialized map values on the console as shown in this figure.

Fields of Deserialized Map

The @RequestBody annotation comes with the required attribute that defaults to true.  Above all, this enforces that a request always contains body content. If not so, an exception is thrown. You can switch this to false if you prefer null to be passed when the body content is null.

The code to do so is this.

@PostMapping("users")
    @ResponseStatus(HttpStatus.CREATED)
    public User registerUserCredential(@RequestBody User user, required=”false”)

The @RequestBody annotation is also commonly used with the @Valid annotation. Both together perform validation of request data. You can read more about it in my post- Bean Validation in Spring Boot

You can find the source code of this post on Github.

For in-depth knowledge of the Spring Framework and Spring Boot, you can check my Udemy Best Seller Course Spring Framework 5: Beginner to Guru

Spring Framework 5

About SFG Contributor

Staff writer account for Spring Framework Guru

    You May Also Like

    One comment

    1. March 23, 2022 at 6:05 am

      Be a darling and share your build file please,
      I need to see which libraries you have depended on and what versions this is referencing.

      Reply

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    This site uses Akismet to reduce spam. Learn how your comment data is processed.