Gson Builder — 基础和命名策略
在本系列之前的博客文章中,我们已经学习了如何使用 Gson 将 Java 对象转换为 JSON,反之亦然。 到目前为止,我们已经介绍了如何设置模型以及为了获得正确的映射而重要的是什么。 通过这篇文章,我们将开始本系列的一个新的篇章,它将使用 GsonBuilder 来自定义 Gson 的行为。
GsonBuilder 基础
在我们之前发布的所有文章中,我们可以通过 Gson gson = new Gson();
获取 Gson 的实例。 当我们需要具有标准配置的 Gson 时,这是完全有效的。 但是,Gson 有很多可以更改的小设置。 如果我们需要以稍微不标准的方式使用 Gson,这将非常方便。 为了更改某些设置,我们可以使用 GsonBuilder 使用我们的自定义配置创建一个新的 Gson 实例。
// 之前使用 Gson
Gson gson = new Gson();
// 现在使用 GsonBuilder
GsonBuilder gsonBuilder = new GsonBuilder();
Gson gson = gsonBuilder.create();
GsonBuilder
类提供了一个返回 Gson 实例的 .create()
方法。 使用 Gson 实例,我们可以完成我们之前展示的所有操作:将各种数据转换到 JSON,或将 JSON 转换成相应的数据。
GsonBuilder 命名策略
我们要展示的第一个 GsonBuilder
选项是命名策略。 我们一直假设 Java 模型文件和 API 请求和响应的 JSON 有效负载应用相同的命名模式。 我们已经向大家展示了如何使用 @SerializedName
来更改单个模型属性的序列化。 但是,如果 API 和 Java 模型在命名上不一致,那么使用 @SerializedName
注解更改数百个属性名称可能会很乏味。
因此,Gson 提供了配置和自定义的 FieldNamingPolicys
。 出于演示目的,我们调整了 UserSimple 模型并为属性赋予了一些新名称:
public class UserNaming {
String Name;
String email_of_developer;
boolean isDeveloper;
int _ageOfDeveloper;
}
如大家所见,我们在一个模型中统一了所有类型的命名标准。 这将产生一些看起来很有趣的 JSON,但更容易看到各种命名策略将如何影响它们。 我们可以在 GsonBuilder
上设置策略:
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.IDENTITY);
Gson gson = gsonBuilder.create();
使用上述 Gson 实例的所有转换现在都将应用字段命名策略 FieldNamingPolicy.IDENTITY
。 在接下来的几节中,我们将探讨这究竟意味着什么以及预定义字段命名策略的行为方式。 让我们从最简单的开始:IDENTITY
。
FieldNamingPolicy IDENTITY
字段命名策略 IDENTITY
在序列化对象时使用与 Java 模型完全相同的命名。 无论我们设置 Java 模型的命名标准是什么,JSON 都将使用相同的命名标准。 上面我们奇怪命名的模型将产生以下 JSON:
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.IDENTITY);
Gson gson = gsonBuilder.create();
UserNaming user = new UserNaming("jiyik", "jiyik_onmpw@163.com", true, 26);
String usersJson = gson.toJson(user);
usersJson
将包含:
{
"Name": "jiyik",
"_ageOfDeveloper": 26,
"email_of_developer": "jiyik_onmpw@163.com",
"isDeveloper": true
}
如大家所见,没有任何字段名称发生变化。 它从模型中复制了确切的名称。 如果我们没有设置策略或不使用 GsonBuilder
并使用 new Gson()
直接实例化 Gson,它将使用此策略。
FieldNamingPolicy LOWER_CASE_WITH_UNDERSCORES
我们要展示的第二个策略是 LOWER_CASE_WITH_UNDERSCORES
。 命名很清楚,但让我们在示例模型上使用它:
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
Gson gson = gsonBuilder.create();
UserNaming user = new UserNaming("jiyik", "jiyik_onmpw@163.com", true, 26);
String usersJson = gson.toJson(user);
LOWER_CASE_WITH_UNDERSCORES
将根据大写字符拆分属性名称,并将这些大写字符替换为以 _
开头的小写字符。 对于我们的模型,两个属性受到影响:
{
"name": "jiyik",
"_age_of_developer": 26,
"email_of_developer": "jiyik_onmpw@163.com",
"is_developer": true
}
isDeveloper
和 _ageOfDeveloper
被 _
分开了。 请注意,_ageOfDeveloper
的前缀 _
仍然存在! 如果我们不想使用下划线而是更喜欢破折号,那么下一部分可能适合大家。
FieldNamingPolicy LOWER_CASE_WITH_DASHES
我们想展示的第三个选项是 LOWER_CASE_WITH_DASHES
。 它使用与之前的 LOWER_CASE_WITH_UNDERSCORES 相同的系统,但将字段名称分隔替换为 -
。 让我们应用以下代码:
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_DASHES);
Gson gson = gsonBuilder.create();
UserNaming user = new UserNaming("jiyik", "jiyik_onmpw@163.com", true, 26);
String usersJson = gson.toJson(user);
这将产生一个包含以下内容的 usersJson
:
{
"name": "jiyik",
"_age-of-developer": 26,
"email_of_developer": "jiyik_onmpw@163.com",
"is-developer": true
}
请注意它仍然只更改了两个带有大写字母的属性。 _ageOfDeveloper
的前缀下划线或 email_of_developer
的下划线不受影响! 如果我们需要更严格的策略,可以实现自己的逻辑,我们将很快向大家展示。 但在转向自定义策略之前,是时候使用最后两个预定义策略了。
FieldNamingPolicy UPPER_CAMEL_CASE
第四个策略是 UPPER_CAMEL_CASE
,它使第一个字母大写。 希望我们现在知道如何使用 GsonBuilder 应用命名策略:
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE);
Gson gson = gsonBuilder.create();
UserNaming user = new UserNaming("jiyik", "jiyik_onmpw@163.com", true, 26);
String usersJson = gson.toJson(user);
结果 usersJson
将是:
{
"Name": "jiyik",
"_AgeOfDeveloper": 26,
"Email_of_developer": "jiyik_onmpw@163.com",
"IsDeveloper": true
}
我们可以看到这是影响所有四个属性的第一个策略。 它会将它们全部更改为以大写字母开头,即使属性名称以前缀 _
开头。 但是,此策略不会改变分离。 它留下相同的下划线。 下一个稍微改变了单词分隔
FieldNamingPolicy UPPER_CAMEL_CASE_WITH_SPACES
最后一个策略 UPPER_CAMEL_CASE_WITH_SPACES
几乎与 UPPER_CAMEL_CASE
相同。 无论如何,代码几乎相同:
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE_WITH_SPACES);
Gson gson = gsonBuilder.create();
UserNaming user = new UserNaming("jiyik", "jiyik_onmpw@163.com", true, 26);
String usersJson = gson.toJson(user);
让我们看看生成的 usersJson
:
{
"Name": "jiyik",
"_Age Of Developer": 26,
"Email_of_developer": "jiyik_onmpw@163.com",
"Is Developer": true
}
如大家所见,与 UPPER_CAMEL_CASE
相比没有太大变化。 唯一的区别是这两个已经有大写字母的字段在单词之间接收空格。
与 @SerializedName 交互
我们可能想知道策略如何与 @SerializedName
交互。 我们已经在之前的博客文章中演示了 @SerializedName
的用法。 让我们改变我们的 UserNaming 模型来使用@SerializedName
:
public class UserNaming {
String Name;
@SerializedName("emailOfDeveloper")
String email_of_developer;
boolean isDeveloper;
int _ageOfDeveloper;
}
当我们现在应用命名策略时会发生什么? 答案是它不会改变 @SerializedName
的属性。 例如,如果我们使用 UPPER_CAMEL_CASE,它将产生以下 JSON:
{
"Name": "jiyik",
"_AgeOfDeveloper": 26,
"emailOfDeveloper": "jiyik_onmpw@163.com",
"IsDeveloper": true
}
emailOfDeveloper
与 @SerializedName
注解中的完全相同,并且没有获得前缀大写字母。
自定义字段命名
提供的策略与 @SerializedName
结合可能不足以涵盖我们用例。 我们可以实现自己的 FieldNamingPolicy
版本。 由于我们只能将预定义的枚举值传递给 .setFieldNamingPolicy()
方法,因此 Gson 提供了第二种方法 .setFieldNamingStrategy()
。
我们可以将 FieldNamingStrategy 的实例传递给适当的方法。 FieldNamingStrategy 类只有一个方法。 例如,如果我们想删除所有预定义策略都没有的下划线,我们可以使用以下代码片段:
FieldNamingStrategy customPolicy = new FieldNamingStrategy() {
@Override
public String translateName(Field f) {
return f.getName().replace("_", "");
}
};
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingStrategy(customPolicy);
Gson gson = gsonBuilder.create();
UserNaming user = new UserNaming("jiyik", "jiyik_onmpw@163.com", true, 26);
String usersJson = gson.toJson(user);
生成的 JSON 将不再包含任何下划线:
{
"Name": "jiyik",
"ageOfDeveloper": 26,
"emailOfDeveloper": "jiyik_onmpw@163.com",
"isDeveloper": true
}
Gson 只接受一种策略。 因此,我们必须在单个 FieldNamingStrategy 实现中实现自己的逻辑。 如果不止一次调用我们在上面展示的方法之一,它将替换前一个。
反序列化
在这篇文章中,我们只研究了事物的序列化方面。 换句话说,在我们使用 Gson 从 Java 对象转换数据之后,JSON 是什么样子的。 所有这些命名策略在反序列化期间都具有相同的效果。 基本上,如果我们有一个 API 以小写形式返回所有值,并用下划线作为单词之间的分隔符,我们可以使用 LOWER_CASE_WITH_UNDERSCORES
作为策略并在模型中使用常规 Java 命名约定。
举个简单的例子,如果你有以下 JSON:
{
"reviewer_name": "Jiyik"
}
我们可以拥有以下模型:
public class PostReviewer {
String reviewerName;
}
如果我们应用正确的命名策略,即使名称不同,Gson 也会进行映射。
总结
在本篇文章中,我们已经了解了使用 GsonBuilder 的基础知识。 我们查看了自定义 Gson 行为的第一个选项。 特别是,我们向大家展示了在 Java 对象的(反)序列化期间自定义属性命名的各种策略。
我们后面会继续介绍更多 GsonBuilder 功能。 具体来说,我们将介绍一种强制 Gson 序列化空值的方法。
相关文章
Gson 通过@JsonAdapter 自定义(反)序列化
发布时间:2022/07/24 浏览次数:217 分类:编程语言
-
在这篇文章中,我们将展示如何简化(反)序列化的自定义。 所有这些选项都只能通过自定义 Gson 实例和一些样板代码获得。 Gson 2.7 引入了一个简单的注解,我们可以节省大量代码并获
Gson 自定义反序列化基础
发布时间:2022/07/21 浏览次数:81 分类:编程语言
-
在这篇文章中,我们将了解如何实现自定义 Gson 反序列化。 如果服务器以与客户端的应用程序数据模型不匹配的格式向我们发送数据,请继续阅读!
Gson 自定义实例创建器
发布时间:2022/07/14 浏览次数:121 分类:编程语言
-
在这篇文章中,我们将讨论自定义反序列化的另一个组件。 在过去的几篇文章中,我们探讨了如何自定义数据的序列化和反序列化。 在这两种情况下,我们都试图减轻服务器和客户端之
Gson 循环引用的映射
发布时间:2022/07/13 浏览次数:173 分类:编程语言
-
在这篇文章中,我们将讨论一个特别讨厌的话题:循环引用。 我们可能在计算机科学或图表数学课上听说过循环引用。 在更实际的解释中:它处理对象具有指向不同对象的嵌套属性的情
Gson Builder Floats 和 Doubles 的特殊值
发布时间:2022/07/12 浏览次数:193 分类:编程语言
-
在上一篇 Gson 的文章中,我们研究了使 JSON 转换降低标准的选项。 Lenient 允许传入的 JSON 在某种程度上是非标准的,Gson 仍然能够将其解析为 Java 对象。 在这篇文章中,我们将研究一个
Gson 自定义序列化
发布时间:2022/07/11 浏览次数:117 分类:编程语言
-
在这篇文章中,我们将探讨如何自定义 Java 对象的 Gson 序列化。 我们可能想要更改序列化的原因有很多,例如 简化我们的模型以减少发送的数据量或删除个人信息。 现在我们将通过实
Gson 映射 Enum 枚举
发布时间:2022/07/10 浏览次数:156 分类:编程语言
-
在之前的文章中我们介绍了如何映射嵌套对象、数组和列表、Java Map 等。 在这篇文章中,您将学习如何(反)序列化 Java 枚举 Enum。
Gson 如何反序列化多态对象列表
发布时间:2022/07/09 浏览次数:286 分类:编程语言
-
最近,我们遇到了一种情况,我从 REST 端点接收到 JSON 格式的对象列表。 到目前为止,这没有什么不寻常的,也不是问题。 然而,问题是对象是多态的,需要解析子类特定的字段。 以