什么是序列化?
序列化就像把一本书翻译成其他语言的过程:
-
序列化:将Java对象转换为JSON字符串(就像把中文书翻译成英文)
-
反序列化:将JSON字符串转换回Java对象(就像把英文书翻译回中文)
在我们的API开发中,序列化让Java对象能够通过网络传输,被其他系统理解。
基础序列化示例
先来看一个简单的例子:
public class User {private String name;private Integer age;private String email;// 构造方法、getter、setter...
}User user = new User("张三", 25, "zhangsan@example.com");
默认序列化结果:
{"name": "张三","age": 25,"email": "zhangsan@example.com"
}
问题场景:我们的工具检测API
现在有一个响应DTO类
public class ToolDetectionResponse {
private boolean success;
private String msg;
private int total;
private List<ToolItem> tools;
private String archive_id;
private String image_url;
// getter、setter...
}
由于接口文档已经写好了,我们需要处理两种不同的响应情况:
需求分析
-
成功时:返回完整的检测结果
-
失败时:只返回错误信息,不包含数据字段
// 理想中的成功响应
{"success": true,"total": 5,"tools": [...],"archive_id": "...","image_url": "..."
}// 理想中的失败响应
{"success": false,"msg": "错误描述"
}
但是目前失败响应的格式是:
{"success": false,"msg": "错误描述","total": 0, // 不想要的字段!"tools": null, // 不想要的字段!"archive_id": null, // 不想要的字段!"image_url": null // 不想要的字段!
}
引入 @JsonInclude
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ToolDetectionResponse {private boolean success;private String msg;private int total;private List<ToolItem> tools;private String archive_id;private String image_url;
}
@JsonInclude注解用于控制当字段值为空时是否参与序列化。
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ToolDetectionResponse {// 类级别的注解:所有为null的字段都不会被序列化
}
常用参数:
-
NON_NULL:值为null时不序列化 -
NON_EMPTY:值为null或空时不序列化 -
NON_DEFAULT:值为默认值时不序列化
现在失败响应变成了:
{"success": false,"msg": "只支持图片文件","total": 0 // 还是有问题!int类型不能为null,总是会显示0
}
核心问题:基本类型 vs 包装类型
-
int total:基本类型,默认值0,不能为null -
Integer total:包装类型,可以为null
由于接口文档已经写好了,要求不能修改字段类型!
引入@JsonIgnore
//这是我们最终采用的方案,结合了多个注解:
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ToolDetectionResponse {@JsonProperty("success")private boolean success;@JsonProperty("msg")private String msg;// 核心技巧:使用@JsonIgnore隐藏基础字段@JsonIgnoreprivate int total;@JsonProperty("tools")private List<ToolItem> tools;@JsonProperty("archive_id")private String archive_id;@JsonProperty("image_url")private String image_url;/*** 自定义序列化逻辑:只有成功时才序列化total字段*/@JsonProperty("total")public Integer getTotalForJson() {return this.success ? this.total : null;}
}
@JsonIgnore用于完全忽略字段的序列化和反序列化。
@JsonIgnore
private int total; // 这个字段不会被序列化
但这样会完全忽略字段,我们需要的是有条件的序列化。
为了实现"成功时序列化,失败时不序列化"的需求,我们采用组合方案:
@JsonIgnore
private int total; // 基础字段被忽略@JsonProperty("total")
public Integer getTotalForJson() {return this.success ? this.total : null;
}
工作原理:
-
@JsonIgnore让基础字段total不被序列化 -
自定义方法
getTotalForJson()使用@JsonProperty("total")声明要序列化的字段 -
方法内根据
success字段决定返回值:-
成功:返回实际的total值
-
失败:返回
null,由于类上有@JsonInclude(NON_NULL),所以不会被序列化
-