Jackson学习笔记

1 简介

Jackson 是一个用于处理 JSON 数据的 Java 类库,广泛应用于 Java Web 后端开发中,尤其是在 Spring Boot 中几乎是默认的 JSON 解析库。Jackson 提供了从 Java 对象到 JSON(序列化)以及从 JSON 到 Java 对象(反序列化)的高效转换。

Jackson 主要由以下模块组成:

模块名 作用说明
jackson-core JSON 的读取和写入的底层实现
jackson-databind core 基础上提供 POJO 映射功能
jackson-annotations 提供 Jackson 注解

通常使用的是 jackson-databind,它会自动依赖上述三个模块。

maven依赖:

1
2
3
4
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>

2 注解

2.1 @JsonProperty

作用:指定 JSON 字段名称。

1
2
3
4
5
{
"FLIGHTID": "xxx"
}
@JsonProperty("FLIGHTID")
private String flightID;

可以对"FLIGHT": "xxx"进行(反)序列化。

2.2 @JsonIgnore

作用:忽略某个字段,不参与序列化和反序列化

1
2
@JsonIgnore
private String flightID;

2.3 @JsonFormat

作用:格式化时间、日期等字段(通常用于 Date, LocalDateTime

1
2
3
4
5
6
{
"RegisterTime": "2025-05-27 00:00:00"
}
@JsonProperty("RegisterTime")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime registerTime;
1
2
3
4
5
6
{
"time": "2025-05-27 00:00:00.000"
}
@JsonProperty("time")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss.SSS", timezone = "Asia/Shanghai")
private Date time;
1
2
3
4
5
6
{
"TIMEOFTRACK": 1744613619739
}
@JsonProperty("TIMEOFTRACK")
@JsonFormat(shape = JsonFormat.Shape.NUMBER, timezone = "Asia/Shanghai")
private Instant timeOfTrack;

3 ObjectMapper

使用ObjectMapper类进行序列化和反序列化,这个类的对象可以重复使用。

  • 序列化:readValue(jsonString, 类.class),返回类对象
  • 反序列化:writeValueAsString(类对象),返回jsonString

使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Service
public class AirportDataServiceImpl implements AirportDataService {
// 可以重复使用
private final static ObjectMapper objectMapper = new ObjectMapper();
@Override
public void saveWeatherInfo(String message) {
if (StringUtils.isEmpty(message)) {
logger.warn("气象数据消息为空: {}", message);
return;
}
try {
// 反序列化
AirportWeatherInfoMessage airportWeatherInfoMessage = objectMapper.readValue(message, AirportWeatherInfoMessage.class);
// 数据入库
String id = UUID.randomUUID().toString().replaceAll("-", "");
// 反序列化
this.airportMessageMapper.saveAndUpdate(id, FlightWebsocketEnum.WEATHER.getIndex(), objectMapper.writeValueAsString(airportWeatherInfoMessage));
} catch (JsonProcessingException e) {
logger.error("解析气象数据信息JSON数据出错{}", message, e);
}
}
}

在 Jackson 反序列化(JSON → Java 对象) 时,如果 JSON 中 缺少某个字段,默认行为是:Jackson 会使用 Java 对象的默认值

例如:

字段类型 默认值
int 0
long 0L
boolean false
double 0.0
String null
Object null
List, Map null(除非自定义默认值)

4 示例

4.1 单一字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Data
public class AirportWeatherInfoMessage {
@JsonProperty("CLOUDAMOUNT")
private String cloudAmount;

@JsonProperty("VISERT")
private String visert;

@JsonProperty("WINDDIR")
private String windDir;

@JsonProperty("WINDSPEED")
private String windSpeed;

@JsonProperty("VISIBILITY")
private String visibility;

@JsonProperty("RVR")
private String rvr;

@JsonProperty("WEATHER")
private String weather;

@JsonProperty("TEMP")
private String temp;

@JsonProperty("QNH")
private String qnh;
}

4.2 数组

假设json消息为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"data": [
"apronID": "xxx",
"callsign": "xxx",
"predict": "xxx",
"msg": [
{
"kpName": "xxx",
"kpName_CN": "xxx",
"SN": "xxx",
"time": "2025-05-27 00:00:00"
}
]
]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
@Data
public class AirportGateProcessMessage {

@JsonProperty("data")
private List<ApronData> data;

@Data
public static class ApronData {
@JsonProperty("apronID")
private String apronID;

@JsonProperty("predict")
private String predict;

@JsonProperty("callsign")
private String callSign;

@JsonProperty("msg")
@JsonDeserialize(using = MessageDataDeserializer.class)
private List<MessageData> messageData;
}

@Data
public static class MessageData {
@JsonProperty("kpName")
private String kpName;

@JsonProperty("kpName_CN")
private String kpNameCN;

@JsonProperty("SN")
private String SN;

@JsonProperty("time")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
private Date time;
}
}

5 自定义反序列化器

接收的消息中,某个字段可能有两个或多个形式:

1
2
3
4
5
6
7
8
9
10
{
"data": [
{
"apronID": "D-168",
"predict": "True",
"callsign": "CSN7079",
"msg": [...] // 数组
}
]
}
1
2
3
4
5
6
7
8
9
10
{
"data": [
{
"msg": "renew", // 👈 是字符串,而不是数组
"apronID": "344",
"predict": "False",
"callsign": "CSN7079",
}
]
}

对应的类假设为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
@Data
public class AirportGateProcess {

@JsonProperty("data")
private List<ApronData> data;

@Data
public static class ApronData {
@JsonProperty("apronID")
private String apronID;

@JsonProperty("predict")
private String predict;

@JsonProperty("callsign")
private String callSign;

@JsonProperty("msg") // 默认是采用数组接收,但可能为字符串
private List<MessageData> messageData;
}

@Data
public static class MessageData {
@JsonProperty("kpName")
private String kpName;

@JsonProperty("kpName_CN")
private String kpNameCN;

@JsonProperty("SN")
private String SN;

@JsonProperty("time")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
private Date time;
}
}

这会导致 Jackson 在反序列化时抛出类型不匹配错误,因为声明的是 List<MessageData>,但 JSON 给的是 "msg": "renew"

1
AirportGateProcess airportGateProcess = objectMapper.readValue(message, airportGateProcess.class); // 抛出类型不匹配错误

解决方案:自定义反序列化器

配合一个自定义的反序列化器,当 JSON 是字符串时自动转换为 List<MessageData>,内容为一个特殊 MessageData(比如 kpName = "renew")。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class MessageDataDeserializer extends JsonDeserializer<List<AirportGateProcess.MessageData>> {

@Override
public List<AirportGateProcess.MessageData> deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException, JsonProcessingException {

ObjectCodec codec = p.getCodec();
JsonNode node = codec.readTree(p);
List<AirportGateProcess.MessageData> list = new ArrayList<>();

if (node.isArray()) {
// 正常数组解析
for (JsonNode item : node) {
AirportGateProcess.MessageData data = codec.treeToValue(item, AirportGateProcess.MessageData.class);
list.add(data);
}
} else if (node.isTextual()) {
// 是字符串时,比如 "renew"
AirportGateProcess.MessageData data = new AirportGateProcess.MessageData();
data.setKpName(node.asText());
list.add(data);
}

return list;
}
}

AirportGateProcess.ApronData 上添加注解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Data
public static class ApronData {
@JsonProperty("apronID")
private String apronID;

@JsonProperty("predict")
private String predict;

@JsonProperty("callsign")
private String callSign;

@JsonProperty("msg")
@JsonDeserialize(using = MessageDataDeserializer.class) // 使用自定义反序列化器
private List<MessageData> messageData;
}

解析结果:

1
2
3
4
5
6
7
8
9
10
11
{
"data": [
{
"msg": "renew",
"apronID": "344",
"predict": "false"
}
]
}
// 解析结果
messageData = [{ kpName: "renew", kpNameCN: null, SN: null, time: null } ]