关于JSON/Gson序列化和非序列化的问题

eivgtgni  于 9个月前  发布在  其他
关注(0)|答案(1)|浏览(197)

我对Java中的序列化还很陌生,在阅读它的过程中,我收集到了几个问题。
假设你想对一个json响应进行格式化,这个json响应有一堆字段(例如a,b,c,d,e,f,g,h),但你只想要a,b,c。你试图访问的API是分页的,所以你循环遍历它们。你还声明了一个元数据类,比如Sample.java这样只包含你想要的字段:

@Data 
@NoArgsConstructor
@AllArgsConstructor

public class Sample {
    private String a;
    private String b;
    private String c;
}

字符串
假设你的服务类是这样做的:

UriComponentsBuilder createBranchUri = UriComponentsBuilder.fromUriString(requestUrl);
try { 
    Gson gson = new Gson(); 
    Type sampleListType = new TypeToken<List<Sample>>() {}.getType(); 
    //loop through the pages and make requests JsonArray sampleLines =      paginatedRequest(restTemplate, createBranchUri, "values"); 
    List<Sample> stashLines = gson.fromJson(sampleLines, sampleListType); 
..........


可以吗?这意味着它将处理序列化而不会出错,并正确地为String a,B和c分配值?或者我们只能通过使用这里描述的排除策略或直接索引到json对象中来“排除”字段。换句话说-gson解析响应时的默认行为是什么(在本例中:d,e...),它在Type中找不到等价的变量?另外,顺序重要吗?假设Map的顺序是a,b,c,d....如果我们在Sample中切换a和b的位置会发生什么?

lmyy7pcs

lmyy7pcs1#

@Data 
@NoArgsConstructor
@AllArgsConstructor
public class Sample {
    ...
}

字符串
为了避免误解:Gson只使用无args构造函数,并使用反射设置和获取字段值,而不使用任何setter或getter方法。(唯一的例外是Java Record Classes,其中Gson确实使用args构造函数和访问器方法。)
当gson解析一个响应(在本例中:d,e...)时,它在Type中找不到等价的变量时,默认的行为是什么?
它只是忽略它们。但不幸的是,这也是你目前无法配置的,请参阅Gson issue 188
使用排除策略“排除”字段
Gson的ExclusionStrategy是相反的用例:一个字段存在于你的Java类中,但你不想它被序列化或非序列化。对于简单的情况,你也可以让字段transient排除它。
另外,顺序重要吗?假设Map的顺序是a,B,c,d..
Java类中字段的顺序在从JSON序列化时并不重要,但在序列化为JSON时却很重要。
在大多数情况下,JSON数据中的顺序在格式化时并不重要,在您的用例中很可能也不重要。重要的情况是:

  • JSON对象包含重名的成员。那么通常会使用最后一个出现的成员,例如{"a":1,"a":2}将具有与{"a":2}相同的效果。
  • 您正在将其并行化为MapObjectJsonObject。然后Gson将创建一个Map示例,该示例保留了顺序,例如当您在Map.entrySet()上并行化时可以看到。但是不同的迭代顺序可能对您的应用程序逻辑无关紧要(可能也不应该)。
Type sampleListType = new TypeToken<List<Sample>>() {}.getType(); 
List<Sample> stashLines = gson.fromJson(sampleLines, sampleListType);


在Gson版本>= 2.10中,你可以使用Gson.fromJson(..., TypeToken)重载。你应该更喜欢它们而不是你正在使用的Gson.fromJson(..., Type)重载,因为它们是类型安全的[1]。所以你可以将代码改为:

TypeToken<List<Sample>> sampleListType = new TypeToken<List<Sample>>() {}; 
List<Sample> stashLines = gson.fromJson(sampleLines, sampleListType);


在Java 9中,这变得更加简洁,因为你可以对匿名类使用“钻石形式”:
TypeToken<List<Sample>> sampleListType = new TypeToken<>() {};
在Java 10中,你也可以使用var
var sampleListType = new TypeToken<List<Sample>>() {};
[1]例如,Gson.fromJson(..., Type)允许您编写这样的非类型安全代码,它可以在没有警告的情况下编译,但在运行时失败:

// Note: Mismatch between `WrongClass` and `MyClass`
List<WrongClass> list = new Gson().fromJson("[{}]", new TypeToken<List<MyClass>>() {}.getType());
// Throws ClassCastException
WrongClass first = list.get(0);

相关问题