jackson 使用文档#
引入 jackson#
在 gradle 中引入 jackson
implementation("com.fasterxml.jackson.core:jackson-core:2.14.3")
implementation("com.fasterxml.jackson.core:jackson-annotations:2.14.3")
implementation("com.fasterxml.jackson.core:jackson-databind:2.14.3")
implementation("com.fasterxml.jackson.core:jackson-core:2.14.3")
implementation("com.fasterxml.jackson.core:jackson-annotations:2.14.3")
implementation("com.fasterxml.jackson.core:jackson-databind:2.14.3")
implementation("com.fasterxml.jackson.core:jackson-module-kotlin:2.14.3")
jackson 配置#
ObjectMapper objectMapper = new ObjectMapper();
// 设置为蛇形命名风格,即 {"user_age": "tom"} => User(userAge="tom")
objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
// 反序列化时,遇到额外不识别字段,不会导致失败
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
jackson 的 spring 配置#
大部分情况下,spring 默认会生成一个 jackson 的 ObjectMapper Bean.
可以在 application.properties 中通过 spring.jackson.*
系列配置完成 jackson 的设置。
例如设置命名风格:
spring.jackson.propertyNamingStrategy = SNAKE_CASE
所有可用配置项见 org.springframework.boot.autoconfigure.jackson.JacksonProperties
。
常用对象转换#
// String userText = "{\"name\": \"jack\", \"age\": 10}";
// User user = new User("jack", 10);
ObjectMapper objectMapper = new ObjectMapper();
// 字符串转对象
User user = objectMapper.readValue(userText, User.class);
User user = objectMapper.readValue(userText, new TypeReference<User>() {});
// 字符串转 map
Map<String, Object> map = objectMapper.readValue(userText, new TypeReference<Map<String, Object>>() {});
// map 转对象
User user = objectMapper.convertValue(userMap, User.class);
User user = objectMapper.convertValue(userMap, new TypeReference<Map<String, Object>>() {});
// 对象、map 转字符串
String text = objectMapper.writeValueAsString(user);
配置字段名称#
@JsonProperty
针对单个字段配置
public class User {
// 将 json 中的 "user-name" 字段反序列化为 User::name 字段
// 而非 "name".
@JsonProperty("user-name")
private String name;
}
@JsonNaming
配置单个类的命名风格
// 设置为蛇形命名,则序列化、反序列化的目标为 {"user_name": ..., "user_age": ...}
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public class User {
private String userName;
private Integer userAge;
}
处理 enum#
通过 @JsonValue
指定序列化、反序列化的目标属性。
// objectMapper.writeValueAsString(Color.RED) => "red"
// objectMapper.readValue("red", Color.class) => Color.RED
public enum Color {
RED("red"),
GREEN("green"),
BLUE("blue");
@JsonValue
private final String name;
Color(String name) {
this.name = name
}
}
处理第三方库的 class#
假设第三方库中存在:
public class User {
private String userName;
private Integer userAge;
}
但是我们要把 {"secret-name": "jack", "secret-age": 10}
反序列化为这个对象。
由于无法更改源码,没办法给 User 加上 @JsonProperty
, 这种情况可以借助 Mixin 实现
public class MixinForUser {
@JsonProperty("secret-name")
private String userName;
@JsonProperty("secret-age")
private Integer userAge;
}
objectMapper.addMixIn(User.class, MixinForUser.class);
User user = objectMapper.readValue("{\"secret-name\": \"jack\", \"secret-age\": 10}", User.class)
处理复杂 class 的反序列化#
public abstract class Event {
public final String type;
protected Event(String type) {
this.type = type;
}
}
public class UpdateEvent {
public final UpdateInfo updateInfo;
public UpdateEvent(UpdateInfo updateInfo) {
super("update");
this.updateInfo = updateInfo;
}
}
public class DeleteEvent {
public final DeleteInfo deleteInfo;
public DeleteEvent(DeleteInfo deleteInfo) {
super("delete");
this.deleteInfo = deleteInfo;
}
}
上面一个基类 Event, 派生出两个子类 UpdateEvent/DeleteEvent. 我们的目标是,让下面的代码能自动选择序列化为其中某一个具体的 Event:
Event event = objectMapper.readValue("{\"type\": \"update\", \"updateInfo\": {...}}", Event.class);
// event => UpdateEvent(...)
这种情况就需要自定义反序列化逻辑.
第一步实现 StdDeserializer
public class EventDeserializer extends StdDeserializer<Event> {
public EventDeserializer() {
this(null);
}
public EventDeserializer(Class<?> vc) {
super(vc);
}
@Override
public Item deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
JsonNode node = jp.getCodec().readTree(jp);
String type = node.get("type").asText();
if ("update".equals(type)) {
UpdateInfo updateInfo = ctxt.readTreeAsValue(
node.get("updateInfo"),
UpdateInfo.class
);
return new UpdateEvent(updateInfo);
} else if ("delete".equals(type)) {
DeleteInfo deleteInfo = ctxt.readTreeAsValue(
node.get("deleteInfo"),
deleteInfo.class
);
return new DeleteEvent(deleteInfo);
}
throw JsonProcessingException("unknown type: " + type);
}
}
第二步,将自定义反序列化逻辑绑定到类上
@JsonDeserialize(using = EventDeserializer.class)
public class Event {
...
}