REST Assured 系列汇总 之 REST Assured 43 - Get All Keys From A Nested JSON Object
介绍
我们可能会得到一个嵌套的 JSON Object,它可能还是动态的。一个动态的响应包括很多键值对。例如:一张商务舱机票的福利肯定比一张经济舱机票的多。如果我们有一个 API 订购机票,显然会得到不同的 JSON 响应。JSON 作为 request body也一样。
总之,你需要从一个普通的或嵌套的 JSON Object中得到所有的键值。
前提条件
Required Java Library
因为我们用到 Jackson API, 所以确保导入 Jackson Databind 依赖包。
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.1</version>
</dependency>
Simple JSON Object
JSON Object
{
"firstName": "Animesh",
"lastName": "Prashant"
}
利用 Java MAP
我们可以将一个 JSON Object 反序列化 deserialization 成 Java Map,我们就很容易得到所有的键值对。
import java.util.Map;
import java.util.Set;
import org.junit.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<String, String> parsedJsonObject = objectMapper.readValue(jsonObject,
new TypeReference<Map<String, String>>() {
});
// Get all keys
Set<String> allKeys = parsedJsonObject.keySet();
System.out.println("All keys are : ");
allKeys.stream().forEach(k -> System.out.println(k));
}
}
输出:
All keys are :
firstName
lastName
利用 JSONNode:
需要用到一个方法 “ObjectMapper” 类提供的 “readTree()”,这个方法将 JSON 内容反序列化 deserialization 成一系列 JsonNode 组成的树形结构。JsonNode 是所有 JSON nodes的一个基类,基于 Jackson 实现的 JSON Tree 模块。好比 XML DOM Trees 中的 DOM nodes。
import java.util.Iterator;
import org.junit.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<String> allKeys= parsedJsonObject.fieldNames();
System.out.println("All keys are : ");
allKeys.forEachRemaining(k -> System.out.println(k));
}
}
输出:
All keys are :
firstName
lastName
Nested JSON Object
JSON Object:
{
"firstName": "Animesh",
"lastName": "Prashant",
"address": {
"city": "Katihar",
"State": "Bihar"
}
}
如果我们用上面的逻辑从嵌套的 JSON Object里获取所有键值,我们将拿不到 “city” 和 “state” 键值。所以,我们需要额外的逻辑判断键的值是否是一个 JSON Object,如果是,我们要从键的值里获取子键值。
使用 Map
当我们反序列化 deserialize 一个 JSON Object 成 Map时,其实它是 LinkedHashMap 的一个实例,所以我们直接用 LinkedHashMap 取代 Map。
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import org.junit.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<String,Object> parsedJsonObject = objectMapper.readValue(jsonObject, new TypeReference<Map<String, Object>>(){});
// Get all keys
Set<String> 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<String> allKeysOfNestedJsonObject = ((LinkedHashMap<String, ?>)value).keySet();
allKeysOfNestedJsonObject.stream().forEach(k->System.out.println(k));
}
});
}
}
输出:
firstName
lastName
city
State
使用 JsonNode
import java.util.Iterator;
import org.junit.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<String> 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<String> keyss = ((ObjectNode)value).fieldNames();
keyss.forEachRemaining(ke -> System.out.println(ke));
}
});
}
}
输出:
firstName
lastName
city
State