Course – LS (cat=JSON/Jackson)

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE

1. Overview

When testing our REST endpoints, sometimes we want to obtain the response and convert it to an object for further checking and validation. As we know, one way to do this is by using libraries such as RestAssured to validate the response without converting it to an object.

In this tutorial, we’ll explore several ways to get JSON content as an object using MockMVC and Spring Boot.

2. Example Setup

Before we dive in, let’s create a simple REST endpoint we’ll use for testing.

Let’s start with the dependency setup. We’ll add the spring-boot-starter-web dependency to our pom.xml so we can create REST endpoints:

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
</dependency>

Next, let’s define the Article class:

public class Article {
    private Long id;
    private String title;
    
    // standard getters and setters
}

Going further, let’s create the ArticleController with two endpoints, one returning a single article and the other returning a list of articles:

@RestController
@RequestMapping
public class ArticleController {
    @GetMapping("/article")
    public Article getArticle() {
        return new Article(1L, "Learn Spring Boot");
    }

    @GetMapping("/articles")
    public List<Article> getArticles() {
        return List.of(new Article(1L, "Guide to JUnit"), new Article(2L, "Working with Hibernate"));
    }
}

3. Test Class

To test our controller, we’ll decorate our test class with the @WebMvcTest annotation. When we use this annotation, Spring Boot automatically configures MockMvc and starts the context only for the web layer.

Furthermore, we’ll specify only to instantiate the context for an ArticleController controller, which is useful in applications with multiple controllers:

@WebMvcTest(ArticleController.class)
class ArticleControllerUnitTest {
    @Autowired
    private MockMvc mockMvc;
}

We can also configure MockMVC using the @AutoConfigureMockMvc annotation. However, this approach requires Spring Boot to run the whole application context, which would make our tests run slower.

Now that we’re all set up, let’s explore how to perform the request using MockMvc and get the response as an object.

4. Using Jackson

One way to transform JSON content into an object is to use the Jackson library.

4.1. Get a Single Object

Let’s create a test to verify the HTTP GET /article endpoint works as expected.

Since we want to convert the response into an object, let’s first call the andReturn() method on the mockMvc to retrieve the result:

MvcResult result = this.mockMvc.perform(get("/article"))
  .andExpect(status().isOk())
  .andReturn();

The andReturn() method returns the MvcResult object, which allows us to perform additional verifications that aren’t supported by the tool.

In addition, we can call the getContentAsString() method to retrieve the response as a String. Unfortunately, MockMvc doesn’t have a defined method we can use to convert the response into a specific object type. We need to specify the logic ourselves.

We’ll use Jackson’s ObjectMapper to convert the JSON content into a desired type.

Let’s call the readValue() method and pass the response in String format along with the type we want to convert the response into:

String json = result.getResponse().getContentAsString();
Article article = objectMapper.readValue(json, Article.class);

assertNotNull(article);
assertEquals(1L, article.getId());
assertEquals("Learn Spring Boot", article.getTitle());

4.2. Get a Collection of Objects

Let’s see how to get the response when the endpoint returns a collection.

In the previous section, we specified the type as Article.class when we wanted to obtain a single object. However, this isn’t possible with generic types such as collections. We can’t specify the type as List<Article>.class.

One way we can deserialize the collection with Jackson is by using the TypeReference generic class:

@Test
void whenGetArticle_thenReturnListUsingJacksonTypeReference() throws Exception {
    MvcResult result = this.mockMvc.perform(get("/articles"))
      .andExpect(status().isOk())
      .andReturn();

    String json = result.getResponse().getContentAsString();
    List<Article> articles = objectMapper.readValue(json, new TypeReference<>(){});

    assertNotNull(articles);
    assertEquals(2, articles.size());
}

Due to type erasure, generic type information isn’t available at runtime. To overcome this limitation, the TypeReference, at compile time, captures the type we want to convert the JSON into.

Additionally, we can achieve the same functionality by specifying the CollectionType:

String json = result.getResponse().getContentAsString();
CollectionType collectionType = objectMapper.getTypeFactory().constructCollectionType(List.class, Article.class);
List<Article> articles = objectMapper.readValue(json, collectionType);

assertNotNull(articles);
assertEquals(2, articles.size());

5. Using Gson

Now, let’s see how to convert JSON content to an object using Gson library.

First, let’s add the required dependency in the pom.xml:

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.10.1</version>
</dependency>

5.1. Get a Single Object

We can transform JSON to an object by calling the fromJson() method on the Gson instance, passing the content and the desired type:

@Test
void whenGetArticle_thenReturnArticleObjectUsingGson() throws Exception {
    MvcResult result = this.mockMvc.perform(get("/article"))
      .andExpect(status().isOk())
      .andReturn();

    String json = result.getResponse().getContentAsString();
    Article article = new Gson().fromJson(json, Article.class);

    assertNotNull(article);
    assertEquals(1L, article.getId());
    assertEquals("Learn Spring Boot", article.getTitle());
}

5.2. Get a Collection of Objects

Lastly, let’s see how to deal with collections using Gson.

To deserialize a collection with Gson, we can specify the TypeToken:

@Test
void whenGetArticle_thenReturnArticleListUsingGson() throws Exception {
    MvcResult result = this.mockMvc.perform(get("/articles"))
      .andExpect(status().isOk())
      .andReturn();

    String json = result.getResponse().getContentAsString();
    TypeToken<List<Article>> typeToken = new TypeToken<>(){};
    List<Article> articles = new Gson().fromJson(json, typeToken.getType());

    assertNotNull(articles);
    assertEquals(2, articles.size());
}

Here, we defined the TypeToken for the list of Article elements. Then, in the fromJson() method, we called getType() to return the Type object. Gson uses reflection to determine what type of object we want to convert our JSON into.

6. Conclusion

In this article, we learned several ways to retrieve JSON content as an object when working with the MockMVC tool.

To sum up, we can use Jackson’s ObjectMapper to convert the String response into the desired type. When working with collections, we need to either specify TypeReference or CollectionType. Similarly, we can deserialize objects with the Gson library.

As always, the entire source code is available over on GitHub.

Course – LS (cat=JSON/Jackson)

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE
res – Jackson (eBook) (cat=Jackson)
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments