Gson 如何对嵌套对象进行映射
在 Gson — Java-JSON 序列化和反序列化入门 这篇文章中,我们介绍了Gson的基本功能。 在这篇文章中,我们将更多地使用更真实的数据并查看嵌套对象。 我们将了解使用包含额外复杂数据的对象是很容易的。
嵌套对象序列化
我们喜欢通过示例演示功能,所以让我们扩展我们的 UserSimple 模型。 在之前的文章中,用户模型只有几个标准的 Java 类型:
public class UserSimple {
String name;
String email;
boolean isDeveloper;
int age;
}
现在我们的用户也有了一个家庭地址,它有自己的模型类 UserAddress
:
public class UserNested {
String name;
String email;
boolean isDeveloper;
int age;
// 新字段
UserAddress userAddress;
}
public class UserAddress {
String street;
String houseNumber;
String city;
String country;
}
换句话说,当前在 UserNested
模型中表示的用户与地址对象具有额外的一对一关系。 地址在 UserAddress
模型中表示。
在 Java 中,这两个模型可以通过类清晰地分开,我们通过 UserAddress userAddress
字段保留引用。 但是,在 JSON 中,我们没有类或引用。 JSON 中的唯一方法(以后不使用 ID 并将事物绑定在一起)是将用户地址嵌套在用户对象中。 基本上,在 JSON 中,我们只需在字段名称后使用 {}
创建一个新对象:
{
"age": 26,
"email": "zadmei_onmpw@163.com",
"isDeveloper": true,
"name": "zadmei",
"userAddress": {
"city": "beijing",
"country": "china",
"houseNumber": "42A",
"street": "Main Street"
}
}
与其他属性(age、email、…)不同,新的 userAddress
没有直接值。 相反,它有包含在 {}
中的子值。 立即将字段名称后面的括号理解为信号 this-is-a-nested-object 很重要。
理论够了。 是时候看看 Gson 从 UserNested
对象创建了什么。 我们可能会清晰的认出这种模式。 Gson 不需要任何配置。 它会根据传递的类自动推断数据的结构:
UserAddress userAddress = new UserAddress(
"Main Street",
"42A",
"BeiJing",
"China"
);
UserNested userObject = new UserNested(
"zadmei",
"zadmei_onmpw@163.com",
true,
26,
userAddress
);
Gson gson = new Gson();
String userWithAddressJson = gson.toJson(userObject);
userWithAddressJson
字符串的值很有趣:
{
"name": "zadmei",
"email": "zadmei_onmpw@163.com",
"isDeveloper": true,
"age": 26,
"userAddress": {
"street": "Main Street",
"houseNumber": "42A",
"city": "BeiJing",
"country": "China"
}
}
结果完全符合我们的预期。 Gson 正确创建了嵌套的 userAddress
JSON 对象。 当然,我们可以为用户的付款方式或工作地址添加更多的嵌套对象。 即使是嵌套对象也可以有嵌套对象!
在下一部分中,我们将看看另一个方向。 我们如何将复杂的嵌套 JSON 反序列化为 Java 对象?
嵌套对象反序列化
在上面,我们假设模型已经存在,我们只想创建一个匹配的 JSON。 尤其是对于现实世界中的应用程序开发人员来说,情况往往恰恰相反。 API 正在返回一些 JSON,我们需要为该 JSON 创建模型类。
如果大家已经阅读了这篇文章的前几段,那么大家已经对如何创建模型类有所了解。 下面的示例中我们转换一下场景,从用户示例转到一家不错的小餐厅。
{
"name": "火焰兔美食馆",
"owner": {
"name": "zadmei",
"address": {
"city": "BeiJing",
"country": "China",
"houseNumber": "42A",
"street": "Main Street"
}
},
"cook": {
"age": 18,
"name": "Tom",
"salary": 1500
},
"waiter": {
"age": 18,
"name": "Jerry",
"salary": 1000
}
}
这来自我们的 API,我们希望利用 Gson 自动为其创建匹配的 Java 对象。 首先,我们需要对所有一级字段所在的基类进行建模:
public class Restaurant {
String name;
Owner owner;
Cook cook;
Waiter waiter;
}
看看我们如何为 name 创建一个 String 并为其他三个创建额外的 Java 类? 每个人可能得出了不同的结果。 创建 Java 对象并不总是明确的。 例如,基于 JSON,我们看到 cook 和 waiter 嵌套对象具有相同的结构。 我们仍然可以创建一个不同的类,就像我们在上面所做的那样,或者为两者创建一个普通的 Staff 类:
public class Restaurant {
String name;
Owner owner;
Staff cook;
Staff waiter;
}
任何一个都可以。 如果有疑问,我们通常倾向于使用额外的类来避免将来出现并发的问题。 例如,如果厨师模型发生变化,但服务员模型保持不变,那就可能需要更改一堆代码。 因此,我们暂时放弃 Staff 的方案。 当然,我们仍然需要为二级对象创建 Java 模型类:
public class Owner {
String name;
UserAddress address;
}
public class Cook {
String name;
int age;
int salary;
}
public class Waiter {
String name;
int age;
int salary;
}
我们重新使用了第一部分的 UserAddress
。 因为它可以完美进行匹配;-)
尽管如此,我们希望大家了解从 JSON 字符串创建 Java 模型类的过程。 我们需要从顶层到最深层,直到嵌套的 JSON 只剩下常规类型。
主要工作已经完成,我们可以把所有东西都扔给 Gson。 当然,如果我们正确地完成了我们的工作,它将优雅地处理所有事情并只用几行代码创建 Java 对象:
String restaurantJson = "{ 'name':'火焰兔美食馆', 'owner':{ 'name':'zadmei', 'address':{ 'city':'BeiJing', 'country':'China', 'houseNumber':'42A', 'street':'Main Street'}},'cook':{ 'age':18, 'name': 'Tom', 'salary': 1500 }, 'waiter':{ 'age':18, 'name': 'Jerry', 'salary': 1000}}";
Gson gson = new Gson();
Restaurant restaurantObject = gson.fromJson(restaurantJson, Restaurant.class);
restaurantObject 实际上包含Json中的所有信息:
提示:从 JSON 创建 Java 模型类可能是一项乏味的工作。 在掌握了这些概念之后,大家可能想要使用自动化该过程的工具。 我们推荐 jsonschema2pojo.org 。