REST Assured Tutorial 43 – Get All Keys From A Nested JSON Object

Introduction

We may get a nested JSON Object which may be dynamic. The dynamic response may include conditional keys and values. For example- A business class ticket will have more benefits than an economy class ticket. If we have an API that books a ticket then obviously we will have different JSON (Suppose JSON as format) response. The same may apply for the JSON request body as well.

In short, you may need to get all keys from a normal JSON object and nested JSON object. This is an interview question as well. You may be asked just to check the presence of a key in JSON response.

Prerequisite

Required Java Library

Since we are using Jackson API of Java for this example, make sure you have the latest dependency of Jackson Databind in your project classpath. I have used below Jackson dependency for this post:-



    com.fasterxml.jackson.core
    jackson-databind
    2.11.2

Simple JSON Object

Example JSON Object

{
  "firstName": "Animesh",
  "lastName": "Prashant"
}

Using Java MAP

As we know that we can deserialize a JSON Object to Java Map easily. As Map is a key-value pair we can get all keys easily.

package JacksonTutorials;

import java.util.Map;
import java.util.Set;

import org.testng.annotations.Test;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class GetAllKeysFromJsonObject {

	@Test
	public void getAllKeysFromJsonObjectUsingMap() throws JsonMappingException, JsonProcessingException {

		String jsonObject = "{\r\n" + "  \"firstName\": \"Animesh\",\r\n" + "  \"lastName\": \"Prashant\"\r\n" + "}";
		ObjectMapper objectMapper = new ObjectMapper();
		// Deserializing into a Map
		Map parsedJsonObject = objectMapper.readValue(jsonObject,
				new TypeReference>() {
				});
		// Get all keys
		Set allKeys = parsedJsonObject.keySet();
		System.out.println("All keys are : ");
		allKeys.stream().forEach(k -> System.out.println(k));

	}

}
Output
All keys are : 
firstName
lastName

Using JsonNode

We need to use a method “readTree()” provided by “ObjectMapper” class which is overloaded. Method “readTree()” is to deserialize JSON content as tree expressed using a set of JsonNode instances. JsonNode is a base class for all JSON nodes, which form the basis of the JSON Tree Model that Jackson implements. One way to think of these nodes is to consider them similar to DOM nodes in XML DOM trees. Source – Jackson Java Doc

package JacksonTutorials;

import java.util.Iterator;
import org.testng.annotations.Test;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

public class GetAllKeysFromJsonObject {

	@Test
	public void getAllKeysFromJsonObjectUsingObjectMapper() throws JsonMappingException, JsonProcessingException
	{
		
		String jsonObject = "{\r\n" + 
				"  \"firstName\": \"Animesh\",\r\n" + 
				"  \"lastName\": \"Prashant\"\r\n" + 
				"}";
		ObjectMapper objectMapper = new ObjectMapper();
		// Converting JSON Object string to JsonNode
		JsonNode parsedJsonObject = objectMapper.readTree(jsonObject);
		// Get all fields or keys
		Iterator allKeys= parsedJsonObject.fieldNames();
		System.out.println("All keys are : ");
		allKeys.forEachRemaining(k -> System.out.println(k));
	}
}
Output
All keys are : 
firstName
lastName

Nested JSON Object

Example JSON Object

{
  "firstName": "Animesh",
  "lastName": "Prashant",
  "address": {
    "city": "Katihar",
    "State": "Bihar"
  }
}

If we use the above logic to get keys from the nested JSON object we will not get keys “city” and “state”. So here we need to put extra logic to check if the value of a key is a JSON Object. If yes then we need to get keys from that as well.

Using Map

When we deserialize a JSON Objects to Map then it is actually an instance of LinkedHashMap. We can use LinkedHashMap directly instead of Map.

package JacksonTutorials;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

import org.testng.annotations.Test;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class GetAllKeysFromJsonObject {

	@Test
	public void getAllKeysFromNestedJsonObjectUsingMap() throws JsonMappingException, JsonProcessingException
	{
		
		String jsonObject = "{\r\n" + 
				"  \"firstName\": \"Animesh\",\r\n" + 
				"  \"lastName\": \"Prashant\",\r\n" + 
				"  \"address\": {\r\n" + 
				"    \"city\": \"Katihar\",\r\n" + 
				"    \"State\": \"Bihar\"\r\n" + 
				"  }\r\n" + 
				"}";
		ObjectMapper objectMapper = new ObjectMapper();
		// Deserialize into Map
		Map parsedJsonObject = objectMapper.readValue(jsonObject, new TypeReference>(){});
		// Get all keys
		Set allKeys = parsedJsonObject.keySet();
		// Iterate keys
		allKeys.stream().forEach(key -> {
			Object value = parsedJsonObject.get(key);
			// If value is a String. You may need to add more if value is of different types
			if(value instanceof String)
				System.out.println(key);
			// If value is another JSON Object which will be LinkedHashMap. You can see this while debugging
			else if(value instanceof LinkedHashMap)
			{
				@SuppressWarnings("unchecked")
				Set allKeysOfNestedJsonObject  = ((LinkedHashMap)value).keySet();
				allKeysOfNestedJsonObject.stream().forEach(k->System.out.println(k));
			}
		});
		
	}
}
Output
firstName
lastName
city
State

Using JsonNode

package JacksonTutorials;

import java.util.Iterator;
import org.testng.annotations.Test;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;

public class GetAllKeysFromJsonObject {

	@Test
	public void getAllKeysFromNestedJsonObjectUsingJsonNode() throws JsonMappingException, JsonProcessingException
	{
			String jsonObject = "{\r\n" + 
					"  \"firstName\": \"Animesh\",\r\n" + 
					"  \"lastName\": \"Prashant\",\r\n" + 
					"  \"address\": {\r\n" + 
					"    \"city\": \"Katihar\",\r\n" + 
					"    \"State\": \"Bihar\"\r\n" + 
					"  }\r\n" + 
					"}";
			ObjectMapper objectMapper = new ObjectMapper();
			JsonNode parsedJsonObject = objectMapper.readTree(jsonObject);
			Iterator allKeys= parsedJsonObject.fieldNames();
			allKeys.forEachRemaining(k -> {
				Object value = parsedJsonObject.get(k);
				// TextNode can be related to String from previous example
				// You may need to add IntNode or BooleanNode for different types of values
				if(value instanceof TextNode)
					System.out.println(k);
				// ObjectNode can be related to LinkedHashMap from previous example
				else if(value instanceof ObjectNode)
				{
					Iterator keyss = ((ObjectNode)value).fieldNames();
					keyss.forEachRemaining(ke -> System.out.println(ke));
				}
		
		});
		
	
	}
	
}

Output
firstName
lastName
city
State

You can download/clone the above sample project from here.

If you have any doubt, feel free to comment below.
If you like my posts, please like, comment, share and subscribe.
#ThanksForReading
#HappyLearning

Find all Selenium related posts here, all API manual and automation related posts here, and find frequently asked Java Programs here.

Many other topics you can navigate through the menu.

Leave a Reply

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