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;
|
作用:格式化时间、日期等字段(通常用于 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()) { 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 } ]
|
著作権表示: 此文章版权归Kisugi Takumi所有,如有转载,请注明来自原作者