走进Java接口测试之fastjson指南

举报
zuozewei 发表于 2021/09/20 17:19:42 2021/09/20
【摘要】 fastjson 是阿里巴巴的开源 JSON 解析库,它可以解析 JSON 格式的字符串,支持将 Java Bean 序列化为 JSON 字符串,也可以从 JSON 字符串反序列化到 JavaBean。

引言

在上文 走进Java接口测试之理解JSON和XML基础 我们介绍了 JSON 的基础知识,本文我们深入研究阿里巴巴的开源 JSON 解析库 fastjson。

什么是fastjson?

fastjson 是阿里巴巴的开源 JSON 解析库,它可以解析 JSON 格式的字符串,支持将 Java Bean 序列化为 JSON 字符串,也可以从 JSON 字符串反序列化到 JavaBean。

截止2019/2/1:

  • Github Stars: 16434
  • Github Forks: 4661

GitHub:https://github.com/alibaba/fastjson/

fastjson的特点

速度快

fastjson 相对其他 JSON 库的特点是快,从 2011 年 fastjson 发布1.1.x版本之后,其性能从未被其他 Java 实现的 JSON 库超越。

使用广泛

fastjson 在阿里巴巴大规模使用,在数万台服务器上部署,fastjson 在业界被广泛接受。在 2012 年被开源中国评选为最受欢迎的国产开源软件之一。

测试完备

fastjson 有非常多的 testcase,在1.2.11版本中,testcase 超过3321个。每次发布都会进行回归测试,保证质量稳定。

使用简单

fastjson 的 API 十分简洁。

String text = JSON.toJSONString(obj); //序列化
VO vo = JSON.parseObject("{...}", VO.class); //反序列化

功能完备

支持泛型,支持流处理超大文本,支持枚举,支持序列化和反序列化扩展。

fastjson使用

Maven配置

为了开始使用FastJson,我们首先需要将它添加到我们的 pom.xml

  <!--引入效率插件-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--引入FastJson包-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.47</version>
        </dependency>
        <!--引入testng测试框架-->
        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>6.14.3</version>
        </dependency>

将Java对象转换为JSON格式

让我们定义以下Person Java bean

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Person {

   	@JSONField(name = "AGE")
    private int age;

    @JSONField(name = "FULL NAME")
    private String fullName;

    @JSONField(name = "DATE OF BIRTH")
    private Date dateOfBirth;
}

我们可以使用 JSON.toJSONString() 将 Java 对象转换为 JSON 字符串

private List<Person> listOfPersons;

	@BeforeTest
	public void setUp() {
		listOfPersons = new ArrayList<Person>();
		// 获取当前时间,取得一个Calendar的实例
		Calendar calendar = Calendar.getInstance();
		// 设置日历
		calendar.set(2019, 01, 31);
		// 实例化Java对象
		listOfPersons.add(new Person(15, "John Doe", calendar.getTime()));
		listOfPersons.add(new Person(20, "Janette Doe", calendar.getTime()));
	}

	@Test(description = "将Java对象转换为JSON格式")
	public void whenJavaList_thanConvertToJsonCorrect() {

		// 将Java对象转换为JSON字符串
		String personJsonFormat = JSON.toJSONString(listOfPersons);
}

这是结果:

[  
    {  
        "AGE":15,
        "DATE OF BIRTH":1468962431394,
        "FULL NAME":"John Doe"
    },
    {  
        "AGE":20,
        "DATE OF BIRTH":1468962431394,
        "FULL NAME":"Janette Doe"
    }
]

我们还可以进一步开始自定义输出并控制排序,日期格式或序列化标志等内容。
例如 - 让我们更新 bean 并添加几个字段:

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Person {

	// 忽略序列化和反序列化
	@JSONField(name = "AGE", serialize = false, deserialize = false)
	private int age;

	// ordinal指定顺序
	@JSONField(name = "LAST NAME", ordinal = 2)
	private String lastName;

	@JSONField(name = "FIRST NAME", ordinal = 1)
	private String firstName;

	// format格式化
	@JSONField(name = "DATE OF BIRTH", format = "dd/MM/yyyy",ordinal = 3)
	private Date dateOfBirth;

}

以下是我们可以与 @JSONField 注解一起使用的最基本参数列表,以便自定义转换过程:

  • 参数格 format 用于正确格式化日期属性
  • 默认情况下,fastjson 库完全序列化Java bean,但我们可以使用参数 -serialize来忽略特定字段的序列化
  • 参数 ordinal 用于指定字段顺序

这是新的输出:

[
    {
        "FIRST NAME":"Doe",
        "LAST NAME":"Jhon",
        "DATE OF BIRTH":"31/01/2019"
    },
    {
        "FIRST NAME":"Doe",
        "LAST NAME":"Janette",
        "DATE OF BIRTH":"31/01/2019"
    }
]

fastjson 还支持非常有趣的 BeanToArray 序列化功能:

String jsonOutput= JSON.toJSONString(listOfPersons, SerializerFeature.BeanToArray);

这是在这种情况下输出的样子:

[
    [
        15,
        1469003271063,
        "John Doe"
    ],
    [
        20,
        1469003271063,
        "Janette Doe"
    ]
]

完整示例:

private List<Person> listOfPersons;

	@BeforeTest
	public void setUp() {
		listOfPersons = new ArrayList<Person>();
		// 获取当前时间,取得一个Calendar的实例
		Calendar calendar = Calendar.getInstance();
		// 设置日历
		calendar.set(2019, 01, 31);
		// 实例化Java对象
		listOfPersons.add(new Person(15, "John", "Doe", calendar.getTime()));
		listOfPersons.add(new Person(20, "Janette", "Doe", calendar.getTime()));
	}

	@Test(description = "将Java对象转换为JSON格式")
	public void whenJavaList_thanConvertToJsonCorrect() {

		// 将Java对象转换为JSON字符串
		String personJsonFormat = JSON.toJSONString(listOfPersons);
		// 断言字符串是否相同
		Assert.assertEquals(personJsonFormat, "[{\"FIRST NAME\":\"Doe\",\"LAST NAME\":\"John\",\"DATE OF BIRTH\":"
				+ "\"01/02/2019\"},{\"FIRST NAME\":\"Doe\",\"LAST NAME\":\"Janette\",\"DATE OF BIRTH\":"
				+ "\"01/02/2019\"}]");
	}

创建JSON对象

与其他 JSON 库一样,从头开始创建 JSON 对象非常简单,只需要组合JSONObject 和 JSONArray 对象:

@Test(description = "创建JSON对象")
	public void whenGenerateJson_thanGenerationCorrect() {
		// 组合JSONObject和JSONArray对象
		JSONArray jsonArray = new JSONArray();
		for (int i = 0; i < 2; i++) {
			JSONObject jsonObject = new JSONObject();
			jsonObject.put("FIRST NAME", "John" + i);
			jsonObject.put("LAST NAME", "Doe" + i);
			jsonObject.put("DATE OF BIRTH", "2019/2/1 12:12:12");
			jsonArray.add(jsonObject);
		}

		Assert.assertEquals(jsonArray.toString(), "[{\"LAST NAME\":\"Doe0\",\"DATE OF BIRTH\":"
				+ "\"2019/2/1 12:12:12\",\"FIRST NAME\":\"John0\"},{\"LAST NAME\":\"Doe1\","
				+ "\"DATE OF BIRTH\":\"2019/2/1 12:12:12\",\"FIRST NAME\":\"John1\"}]");
		System.out.println(jsonArray.toString());
	}

以下是输出结果:

[
   {
      "LAST NAME":"Doe0",
      "DATE OF BIRTH":"2019/2/1 12:12:12",
      "FIRST NAME":"John0"
   },
   {
      "LAST NAME":"Doe1",
      "DATE OF BIRTH":"2019/2/1 12:12:12",
      "FIRST NAME":"John1"
   }
]

将JSON字符串解析为Java对象

现在我们知道如何从头开始创建 JSON 对象,以及如何将 Java 对象转换为它们的 JSON 格式,让我们把重点放在如何解析 JSON 格式上:

@Test(description = "将JSON字符串解析为Java对象")
	public void whenJson_thanConvertToObjectCorrect() {
		// 将Java对象转换为JSON字符串
		String personJsonFormat = JSON.toJSONString(listOfPersons.get(0));
		System.out.println(personJsonFormat);

		// 从JSON字符串中获取Java对象
		Person newPerson = JSON.parseObject(personJsonFormat, Person.class);
		System.out.println(newPerson.toString());

		// 使用参数serialize忽略Age字段的序列化
		Assert.assertEquals(newPerson.getAge(), 0);
		System.out.println(newPerson.getAge());

		Assert.assertEquals(newPerson.getFirstName(), listOfPersons.get(0).getFirstName());
		System.out.println(newPerson.getFirstName());

		Assert.assertEquals(newPerson.getLastName(), listOfPersons.get(0).getLastName());
		System.out.println(newPerson.getLastName());
	}

我们可以使用 JSON.parseObject() 从 JSON 字符串中获取 Java 对象。
请注意,如果已经声明了自己的参数化构造函数,则必须定义no-args 或默认构造函数,否则将抛出 com.alibaba.fastjson.JSONException

这是新创建的对象。

Person(age=0, lastName=John, firstName=Doe, dateOfBirth=Sun JAN 31 00:00:00 CST 2019)

使用ContextValueFilter配置JSON转换

在某些情况下,我们可能需要更多地控制从 Java 对象到 JSON 格式的转换过程。
在这种情况下,我们可以使用 ContextValueFilter 对象对转换流应用其他过滤和自定义处理:

@Test(description = "使用ContextValueFilter配置JSON转换")
	public void givenContextFilter_whenJavaObject_thanJsonCorrect() {
		// 使用ContextValueFilter对象对转换流应用其他过滤和自定义处理
		ContextValueFilter valueFilter = new ContextValueFilter() {
			public Object process(BeanContext context, Object object, String name, Object value) {
				// 隐藏了 DATE OF BIRTH 字段,强制一个常量值
				if (name.equals("DATE OF BIRTH")) {
					return "NOT TO DISCLOSE";
				}
				// 忽略了所有不是John或Doe的字段
				if (value.equals("John") || value.equals("Doe")) {
					return ((String) value).toUpperCase();
				} else {
					return null;
				}
			}
		};
		// 将Java对象转换为JSON字符串并过滤及自定义处理
		String personJsonFormat = JSON.toJSONString(listOfPersons, valueFilter);
		System.out.println(personJsonFormat);

	}

在这个例子中,我们隐藏了 DATE OF BIRTH 字段,通过强制一个常量值,我们也忽略了所有不是 John 或 Doe 的字段:

[
   {
      "FIRST NAME":"DOE",
      "LAST NAME":"JOHN",
      "DATE OF BIRTH":"NOT TO DISCLOSE"
   },
   {
      "FIRST NAME":"DOE",
      "DATE OF BIRTH":"NOT TO DISCLOSE"
   }
]

正如你所看到的,这是一个非常基本的示例,当然可以在更复杂的测试场景中使用相同的概念 - 结合 fastjson 在实际项目中提供的这些功能强大且轻量级的工具集。

使用NameFilter和SerializeConfig

fastjson 提供了一组工具来在处理任意对象时自定义 JSON 操作 - 我们没有源码的对象。
让我们假设我们有一个最初在本文中声明的 Person Java bean 的编译版本,我们需要对字段命名和基本格式进行一些增强:

	@Test(description = "使用NameFilter和SerializeConfig")
	public void givenSerializeConfig_whenJavaObject_thanJsonCorrect() {

		// formatName过滤器来处理字段名称。
		NameFilter formatName = new NameFilter() {
			public String process(Object object, String name, Object value) {
				return name.toLowerCase().replace(" ", "_");
			}
		};
		SerializeConfig.getGlobalInstance().addFilter(Person.class, formatName);

		// 将对象转换为JSON格式,快速在日期字段上应用相同的格式规则。
		String jsonOutput = JSON.toJSONStringWithDateFormat(listOfPersons, "yyyy-MM-dd");

		System.out.println(jsonOutput);
		Assert.assertEquals(jsonOutput, "[{\"first_name\":\"Doe\",\"last_name\":\"John\","
				+ "\"date_of_birth\":\"2019-02-01\"},{\"first_name\":\"Doe\",\"last_name\":"
				+ "\"Janette\",\"date_of_birth\":\"2019-02-01\"}]");


		// 重新设置自定义序列化器
		SerializeConfig.getGlobalInstance().put(Person.class, null);
	}

我们使用 NameFilter 匿名类声明了 formatName 过滤器来处理字段名称。新创建的过滤器与 Person 类相关联,然后添加到全局实例 - 它基本上是 SerializeConfig 类中的静态属性。
现在我们可以轻松地将对象转换为 JSON 格式,如本文前面所示。

请注意,我们使用了 toJSONStringWithDateFormat() 而不是 toJSONString() 来快速在日期字段上应用相同的格式规则。

这是输出:

[
   {
      "first_name":"Doe",
      "last_name":"John",
      "date_of_birth":"2019-03-03"
   },
   {
      "first_name":"Doe",
      "last_name":"Janette",
      "date_of_birth":"2019-03-03"
   }
]

如你所见 - 字段名称已更改,日期值确实已正确格式化。
将 SerializeFilter 与 ContextValueFilter 相结合可以完全控制任意和复杂Java 对象的转换过程。

小结

在本文中,我们展示了如何使用 fastjson 将Java bean 转换成 JSON 字符串,以及如何反过来。我们还展示了如何使用 fastjson 的一些核心特性来定制 JSON 输出。
如你所见,fastjson库提供了一个相对简单但仍然非常强大的API。JSON.toJSONStringJSON.parseObject 可满足大多数需求。

本文源码:

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。