REST Assured 系列汇总 之 REST Assured 25 - 用Jackson API的ObjectMapper类创建JSON Object

关于Jackson API

Jackson API是java的高性能JSON处理器。我们利用Jackson API 可以执行serialization系列化,deserialization 反序列化,读/写一个JSON文件。

Maven 依赖:
一般尽量用最新版本的依赖来自Central Maven Repository

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.13.0-rc2</version>
</dependency>

注意:当我们添加jackosn-databind依赖时,传递依赖包jackson-annotationsjackson-core也会自动下载。

当然添加json-schema-validator依赖时,jackosn-databind,jackson-annotationsjackson-core也会自动下载,因为json-schema-validator传递依赖jackosn-databind包。

<!-- json schema validation -->
   <dependency>
      <groupId>io.rest-assured</groupId>
      <artifactId>json-schema-validator</artifactId>
      <version>4.3.0</version>
   </dependency>

jackson添加JavaTimeModule_ObjectMapper

ObjectMapper Class:

ObjectMapper类是Jackson API提供的最强大,我们使用最多的。目前我们只知道ObjectMapper提供读写JSON,我们将以后会了解更多功能。

我们将利用ObjectMapper来创建一个JSON Object或则ObjectNode。

我们以一个熟悉的JSON payload开始,我们将用ObjectMapper来创建它。

{
     "firstname": "Jim",
     "lastname": "Brown",
     "totalprice": 111,
     "depositpaid": true,
     "additionalneeds": "Breakfast",
     "bookingdates": {
         "checkin": "2021-07-01",
         "checkout": "2021-07-01"
     }
 }

上面的JSON是一个嵌套的JSON Object。一个JSON Object是根节点,包含firstname, lastname, totalprice, depositpaid,additionalneeds字段,和bookingdates 另外一个JSON Object。

创建一个 JSON Object 或Object Node

想要用Jackson创建一个JSON Object,我们需要用ObjectMapper中的createObjectNode() 方法,它将返回一个ObjectNode实例。ObjectNode 类有重写方法put(String fieldName, T fieldValue), field name是String类型,value是可以是基础类型或则是包装类等。field names必须是唯一的。如果传重复的field name,不会抛异常而是覆盖原来的值,这也类似Java中Map的put()方法。

为了将创建的JSON Object转换成String,ObjectMapper类提供**writeValueAsString()方法。如果你想要合适的JSON格式,可以用writeWithDefaultPrettyPrinter()**方法进行格式化。

例如:

// Create an object to ObjectMapper
ObjectMapper objectMapper = new ObjectMapper();
		
// Creating Node that maps to JSON Object structures in JSON content
ObjectNode bookingDetails = objectMapper.createObjectNode();
		
// It is similar to map put method. put method is overloaded to accept different types of data
// String as field value
bookingDetails.put("firstname", "Jim");
bookingDetails.put("lastname", "Brown");
// integer as field value
bookingDetails.put("totalprice", 111);
// boolean as field value
bookingDetails.put("depositpaid", true);
bookingDetails.put("additionalneeds", "Breakfast");
// Duplicate field name. Will override value
bookingDetails.put("additionalneeds", "Lunch");
// To print created json object
String createdPlainJsonObject = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(bookingDetails);
System.out.println("Created plain JSON Object is : \n"+ createdPlainJsonObject);

输出:

Created plain JSON Object is : 
{
  "firstname" : "Jim",
  "lastname" : "Brown",
  "totalprice" : 111,
  "depositpaid" : true,
  "additionalneeds" : "Lunch"
}

创键一个嵌套的JSON Object 或Object Node
为了创建嵌套的JSON Object或者将另外一个JSON Object作为一个字段的值,我们使用set(String fieldName, JsonNode fieldValue)replace(String fieldName, JsonNode fieldValue)注意不要使用put(String fieldName, JsonNode fieldValue),这个方法已经被废弃了

例如:

// Since requirement is to create a nested JSON Object
ObjectNode bookingDateDetails = objectMapper.createObjectNode();
bookingDateDetails.put("checkin", "2021-07-01");
bookingDateDetails.put("checkout", "2021-07-01");
		
// Since 2.4 , put(String fieldName, JsonNode value) is deprecated. So use either set(String fieldName, JsonNode value) or replace(String fieldName, JsonNode value)
bookingDetails.set("bookingdates", bookingDateDetails);
		
// To get the created json object as string. Use writerWithDefaultPrettyPrinter() for proper formatting
String createdNestedJsonObject = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(bookingDetails);
System.out.println("Created nested JSON Object is : \n"+ createdNestedJsonObject);

输出:

Created nested JSON Object is : 
{
  "firstname" : "Jim",
  "lastname" : "Brown",
  "totalprice" : 111,
  "depositpaid" : true,
  "additionalneeds" : "Lunch",
  "bookingdates" : {
    "checkin" : "2021-07-01",
    "checkout" : "2021-07-01"
  }
}

我们将看到一些非常有用的解析JSON Object的处理方法。我们可以用这些方法做一些验证。

从JSON Object或ObjectNode中获取字段值
为了获取字段值,我们需要用get(String fieldName),返回一个JsonNode,如果传入的field name没有vlaue或则是不存在这个field name,将返回null。为了获取value的真实数据类型,我们可以用像asText()和asBoolean()方法分别得到String和boolean类型的值。注意小心当value是另外一个ObjectNode

代码:

// We can retrieve field value by passing field name. Since it is string, use asText().
String firstName = bookingDetails.get("firstname").asText();
System.out.println("First name is : "+firstName);
 
// We can use asText() as well but return type will be string
boolean depositpaid = bookingDetails.get("depositpaid").asBoolean();
System.out.println("deposit paid is : "+depositpaid);
 
// To retrieve value of nested ObjectNode
bookingDetails.get("bookingdates").get("checkin").asText();
System.out.println("Checkin date is : "+depositpaid);

输出:

First name is : Jim
deposit paid is : true
Checkin date is : true

获取JSON Object或Object所有字段名
为了获取所有字段名,我们需要用fieldNames()方法,它将返回一个 Iteraltor< String > 想要获取ObjectNode字段个数,可以用**size()**方法。

代码:

// To get all field names
System.out.println("Count of fields in ObjectNode : "+ bookingDetails.size());
Iterator<String> allFieldNames = bookingDetails.fieldNames();
System.out.println("Fields are : ");
while(allFieldNames.hasNext())
{
   System.out.println(allFieldNames.next());
}

输出:

Count of fields in ObjectNode : 6
Fields are : 
firstname
lastname
totalprice
depositpaid
additionalneeds
bookingdates

获取JSON Object或ObjectNode中所有的字段值

为了获取ObjectNode中所有values,用elements() 方法,返回JsonNode的一个Iterator

例如:

// To get all field values
Iterator<JsonNode> allFieldValues = bookingDetails.elements();
System.out.println("Fields values are : ");
while(allFieldValues.hasNext())
{
    System.out.println(allFieldValues.next());
}

输出:

Fields values are : 
"Jim"
"Brown"
111
true
"Lunch"
{"checkin":"2021-07-01","checkout":"2021-07-01"}

获取JSON Object或ObjectNode所有的key-value键值对
fields() 方法获取一个JSON Object所有的字段(包括名字和值),它返回一个 Iterator < Entry < String, JsonNode > >

例如:

// To get all key-value pair
Iterator<Entry<String, JsonNode>> allFieldsAndValues = bookingDetails.fields();
System.out.println("All fields and their values are : ");
while(allFieldsAndValues.hasNext())
{
	Entry<String, JsonNode> node = allFieldsAndValues.next();
	System.out.println("Key is : "+node.getKey()+" and its value is : "+node.getValue());
}

输出:

All fields and their values are : 
Key is : firstname and its value is : "Jim"
Key is : lastname and its value is : "Brown"
Key is : totalprice and its value is : 111
Key is : depositpaid and its value is : true
Key is : additionalneeds and its value is : "Lunch"
Key is : bookingdates and its value is : {"checkin":"2021-07-01","checkout":"2021-07

移除JSON Object或ObjectNode的一个字段
remove(String fieldName) 方法来移除ObjectNode中的一个字段。如果字段存在,将返回这个字段的value,否则返回null

例如:

// To remove a field
String removedFieldValue = bookingDetails.remove("firstname").asText();
System.out.println("Value of Removed field is " + removedFieldValue);
String removedJsonObject = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(bookingDetails);
System.out.println("After removing field , JSON Object is : \n"+ removedJsonObject);

输出:

Value of Removed field is Jim
After removing field , JSON Object is : 
{
  "lastname" : "Brown",
  "totalprice" : 111,
  "depositpaid" : true,
  "additionalneeds" : "Lunch",
  "bookingdates" : {
    "checkin" : "2021-07-01",
    "checkout" : "2021-07-01"
  }
}

更新JSON Object或ObjectNode的一个字段
如果这个字段value不是一个ObjectNode,用put() 方法来更新一个字段的value,如果这个字段的value是ObjectNode,用set()replace() 方法。

例如:

// To replace a field value, use put() method for non ObjectNode type and replace() or set() for ObjectNode
		bookingDetails.put("firstname", "Amod");
		bookingDetails.put("firstname", "Aaditya");
		String updatedJsonObject = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(bookingDetails);
		System.out.println("After updating field , JSON Object is : \n"+ updatedJsonO

输出:

After updating field , JSON Object is : 
{
  "lastname" : "Brown",
  "totalprice" : 111,
  "depositpaid" : true,
  "additionalneeds" : "Lunch",
  "bookingdates" : {
    "checkin" : "2021-07-01",
    "checkout" : "2021-07-01"
  },
  "firstname" : "Aaditya"
}

完整代码

import java.util.Iterator;
import java.util.Map.Entry;
 
import org.testng.annotations.Test;
 
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
 
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
 
public class CreateJsonObjectUsingJacksonAPI {
	
	@Test
	public void CreatingNestedJsonObjectTest() throws JsonProcessingException
	{
		// Create an object to ObjectMapper
		ObjectMapper objectMapper = new ObjectMapper();
		
		// Creating Node that maps to JSON Object structures in JSON content
		ObjectNode bookingDetails = objectMapper.createObjectNode();
		
		// It is similar to map put method. put method is overloaded to accept different types of data
		// String as field value
		bookingDetails.put("firstname", "Jim");
		bookingDetails.put("lastname", "Brown");
		// integer as field value
		bookingDetails.put("totalprice", 111);
		// boolean as field value
		bookingDetails.put("depositpaid", true);
		bookingDetails.put("additionalneeds", "Breakfast");
		// Duplicate field name. Will override value
		bookingDetails.put("additionalneeds", "Lunch");
		// To print created json object
		String createdPlainJsonObject = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(bookingDetails);
		System.out.println("Created plain JSON Object is : \n"+ createdPlainJsonObject);
		
		// Since requirement is to create a nested JSON Object
		ObjectNode bookingDateDetails = objectMapper.createObjectNode();
		bookingDateDetails.put("checkin", "2021-07-01");
		bookingDateDetails.put("checkout", "2021-07-01");
		
		// Since 2.4 , put(String fieldName, JsonNode value) is deprecated. So use either set(String fieldName, JsonNode value) or replace(String fieldName, JsonNode value)
		bookingDetails.set("bookingdates", bookingDateDetails);
		
		// To get the created json object as string. Use writerWithDefaultPrettyPrinter() for proper formatting
		String createdNestedJsonObject = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(bookingDetails);
		System.out.println("Created nested JSON Object is : \n"+ createdNestedJsonObject);
		
		// We can retrieve field value by passing field name. Since it is string, use asText().
		String firstName = bookingDetails.get("firstname").asText();
		System.out.println("First name is : "+firstName);
		
		// We can use asText() as well but return type will be string
		boolean depositpaid = bookingDetails.get("depositpaid").asBoolean();
		System.out.println("deposit paid is : "+depositpaid);
		
		// To retrieve value of nested ObjectNode
		bookingDetails.get("bookingdates").get("checkin").asText();
		System.out.println("Checkin date is : "+depositpaid);
		
		// To get all field names
		System.out.println("Count of fields in ObjectNode : "+ bookingDetails.size());
		Iterator<String> allFieldNames = bookingDetails.fieldNames();
		System.out.println("Fields are : ");
		while(allFieldNames.hasNext())
		{
			System.out.println(allFieldNames.next());
		}
		
		// To get all field values
		Iterator<JsonNode> allFieldValues = bookingDetails.elements();
		System.out.println("Fields values are : ");
		while(allFieldValues.hasNext())
		{
			System.out.println(allFieldValues.next());
		}
		
		// To get all key-value pair
		Iterator<Entry<String, JsonNode>> allFieldsAndValues = bookingDetails.fields();
		System.out.println("All fields and their values are : ");
		while(allFieldsAndValues.hasNext())
		{
			Entry<String, JsonNode> node = allFieldsAndValues.next();
			System.out.println("Key is : "+node.getKey()+" and its value is : "+node.getValue());
		}
		
		// To remove a field
		String removedFieldValue = bookingDetails.remove("firstname").asText();
		System.out.println("Value of Removed field is " + removedFieldValue);
		String removedJsonObject = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(bookingDetails);
		System.out.println("After removing field , JSON Object is : \n"+ removedJsonObject);
		
		// To replace a field value, use put() method for non ObjectNode type and replace() or set() for ObjectNode
		bookingDetails.put("firstname", "Amod");
		bookingDetails.put("firstname", "Aaditya");
		String updatedJsonObject = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(bookingDetails);
		System.out.println("After updating field , JSON Object is : \n"+ updatedJsonObject);
		
	}
 
}

输出:

Created plain JSON Object is : 
{
  "firstname" : "Jim",
  "lastname" : "Brown",
  "totalprice" : 111,
  "depositpaid" : true,
  "additionalneeds" : "Lunch"
}
Created nested JSON Object is : 
{
  "firstname" : "Jim",
  "lastname" : "Brown",
  "totalprice" : 111,
  "depositpaid" : true,
  "additionalneeds" : "Lunch",
  "bookingdates" : {
    "checkin" : "2021-07-01",
    "checkout" : "2021-07-01"
  }
}
First name is : Jim
deposit paid is : true
Checkin date is : true
Count of fields in ObjectNode : 6
Fields are : 
firstname
lastname
totalprice
depositpaid
additionalneeds
bookingdates
Fields values are : 
"Jim"
"Brown"
111
true
"Lunch"
{"checkin":"2021-07-01","checkout":"2021-07-01"}
All fields and their values are : 
Key is : firstname and its value is : "Jim"
Key is : lastname and its value is : "Brown"
Key is : totalprice and its value is : 111
Key is : depositpaid and its value is : true
Key is : additionalneeds and its value is : "Lunch"
Key is : bookingdates and its value is : {"checkin":"2021-07-01","checkout":"2021-07-01"}
Value of Removed field is Jim
After removing field , JSON Object is : 
{
  "lastname" : "Brown",
  "totalprice" : 111,
  "depositpaid" : true,
  "additionalneeds" : "Lunch",
  "bookingdates" : {
    "checkin" : "2021-07-01",
    "checkout" : "2021-07-01"
  }
}
After updating field , JSON Object is : 
{
  "lastname" : "Brown",
  "totalprice" : 111,
  "depositpaid" : true,
  "additionalneeds" : "Lunch",
  "bookingdates" : {
    "checkin" : "2021-07-01",
    "checkout" : "2021-07-01"
  },
  "firstname" : "Aaditya"
}