- FasterXML/jackson-annotations
- FasterXML/jackson-databind
- Jackson Annotation Examples
-
Streaming(
jackson-core
)提供流式解析工具
JsonParser
,流式生成工具JsonGenerator
- Annotations( jackson-annotations )提供注解
-
Databind (
jackson-databind
) 提供
ObjectMapper
用于序列化和反序列化,依赖前两个模块 - 强大灵活的注解和 API
- 通过 Module 模块扩展可支持 XML、YAML、Properties
-
org.springframework.boot:spring-boot-starter-web
默认集成 Jackson,基于 Spring Boot 的 Web 项目可直接使用
Jackson 的核心由三个模块组成
ObjectMapper mapper = new ObjectMapper();
User randomUser = new User();
List<User> users = new ArrayList<>() {{
add(randomUser());
mapper.writeValueAsString(user);
mapper.writeValueAsString(users);
// 反序列化为对象
Foo foo = mapper.readValue(objectStr, Foo.class);
// 反序列化为数组
Foo[] foos = mapper.readValue(arrayStr, Foo[].class);
// 反序列化为基本类型的 List
List<Integer> list = mapper.readValue(arrayStr, List.class);
// 反序列化为复杂类型的 List
List<Foo> list = mapper.readValue(arrayStr, new TypeReference<List<Foo>>() {
// 反序列化为复杂类型的 Map
Map<String, Foo> map = mapper.readValue(objectStr, new TypeReference<Map<String, Foo>>() {
TreeModel
如果业务逻辑只需要 JSON 中的一部分字段,或者 JSON 的结构需要在运行时推导,可用 TreeModel 转换为 JsonNode
来处理。
String objectStr = "{ \"color\" : \"Black\", \"type\" : \"FIAT\" }";
JsonNode node = objectMapper.readTree(json);
String color = node.get("color").asText();
// Output: color -> Black
在 Java 中直接创建 JSON 和 JSONArray 也需要使用 TreeModel
JsonNode node = mapper.valueToTree(fromValue);
// or
JsonNode node = mapper.convertValue(fromValue, JsonNode.class);
// 使用 ObjectMapper
ObjectNode node = mapper.createObjectNode();
ArrayNode nodes = mapper.createArrayNode();
由于值/对象/数组都被视为 JsonNode
,可以使用 isValueNode
,isArray
,isObject
等方法判断
if (column.isArray()) {
for (final JsonNode field : column) {
JsonNode prop = field.get("prop");
if (prop.isValueNode()) {
logger.info("field {} has loaded.", prop.asText());
path
方法可用于按已知路径寻找指定节点
JsonNode located = root.path("name").path("last");
ObjectMapper 常用配置
Spring Boot 项目支持在 application.*
文件的 spring.jackson
路径下配置 ObjectMapper 的部分行为,也可以在代码中使用 configure(SerializationFeature f, boolean state)
或 enable/disable(SerializationFeature f)
配置。
// 序列化
// 空对象不抛出异常
mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS)
// 反序列化
// 允许 JSON 中存在 Bean 未定义的属性
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
// 允许基本类型字段为空
mapper.disable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)
// 空字符串按 null 处理
mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
// 允许枚举序列化为数字
mapper.disable(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS)
registerModule
java.time API
使用 Java 8 提供的 java.time API 类型(例如 java.time.LocalDateTime
和 java.time.OffsetDateTime
)时,需要添加 com.fasterxml.jackson.datatype:jackson-datatype-jsr310
依赖并在初始化 ObjectMapper 时注册 JavaTimeModule
。
mapper.registerModule(new JavaTimeModule());
默认配置下 java.time.OffsetDateTime
会被序列化为一个 Unix Timestamp 如1653448397.096875000
。java.time.LocalDateTime
则会被序列化为一个数组如 [2022,5,25,11,13,17,96975000]
。要取消这一行为(和 Spring MVC 一样处理为 ISO 8601 字符串),使用 .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
。
时间对象的序列化与反序列化参考自定义序列化和反序列化部分。
Optional<T>
类成员是 Optional<T>
时,序列化会获得一个 {"present":true}
,而反序列化会抛出 JsonMappingException
异常。
使用 com.fasterxml.jackson.datatype:jackson-datatype-jdk8
并注册 Jdk8Module
,一个空的 Optional<T>
会被映射为 null
,而反序列化能够正确地填充属性。
objectMapper.registerModule(new Jdk8Module());
同样支持 OptionalLong
和 OptionalDouble
。
@JsonProperty
修饰成员变量和方法,可在 JSON 字段名与类属性名称不一致时指定 JSON 字段的名称。index
可以指定属性在序列化结果中的顺序。
@JsonProperty
修饰的 private
属性即使没有 getter 和 setter 也能被成功序列化和反序列化。
打包处理未知字段
@JsonAnyGetter
和 @JsonAnySetter
可以把未知或动态变化的字段通过 Map 序列化和反序列化。
public class ChangeableUser {
private long id;
private Map<String, String> extendsProperties = new HashMap<>();
@JsonAnyGetter
public Map<String, String> getExtendsProperties() {
return extendsProperties;
@JsonAnySetter
public void addExtendsProperty(String key, String value) {
extendsProperties.put(key, value);
反序列化形如 {"name":"John Doe","age":24,"phone":"123456789","sex":"male","id":2301}
的 JSON 串后,可以通过 extendsProperties
访问未定义的属性。
指定构造函数
Jackson 在反序列化时会选择无参构造函数或 @JsonCreator
修饰的构造函数,这一点在需要做映射操作时比较有用(例如从 code
映射到枚举)。
@JsonValue
和 @JsonCreator
可用于枚举的序列化和反序列化。下方示例告诉 Jackson 在序列化结果中使用 code
,在反序列化过程中映射回枚举。
public enum FruitEnum {
Banana(0, "ba"),
Apple(1, "ap");
final int code;
final String name;
FruitEnum(int code, String name) {
this.code = code;
this.name = name;
@JsonValue
public int getCode() {
return code;
@JsonCreator
public static FruitEnum getFruit(int code) {
for (FruitEnum fruitEnum : FruitEnum.values()) {
if (fruitEnum.getCode() == code) {
return fruitEnum;
return null;
@JsonIgnoreProperties
接受一个属性名称的集合,用于屏蔽 Bean 中的属性,使其不会被添加到序列化结果中,也可以使用 @JsonIgnore
注解单独设置每个属性。
@JsonIgnoreProperties({ "id", "password" })
public class SystemUser {
private long id;
private String name;
private String password;
@JsonIgnore
private String address;
被 @JsonIgnoreType
修饰的类作为其他类的成员时,无论是序列化还是反序列化都会被忽略。
@JsonAutoDetect
注解可以根据 fieldVisibility
的值和属性是否为 public/protected/private
判断是否要在序列化/反序列化过程中处理。
自定义序列化和反序列化
一些复杂对象在序列化和反序列化过程中需要编写一些逻辑代码,例如:
逗号分割的字符串与 List<String>
转换
ISO8601 格式的日期时间字符串与 OffsetDateTime/LocalDateTime
的转换,后者需要额外处理时区信息,或改为使用 DateTimeFormatter.ISO_LOCAL_DATE_TIME
自定义的序列化需要继承 StdSerializer<T>
实现 serialize
方法。
@Override
public void serialize(OffsetDateTime value, JsonGenerator gen, SerializerProvider provider) throws IOException {
gen.writeString(value.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
使用 @JsonSerialize(using = CustomSerializer.class)
修饰属性。
自定义的反序列化操作需要继承 StdDeserializer<T>
实现 deserialize
方法。
@Override
public LocalDateTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
return LocalDateTime.parse(jsonParser.getText(), DateTimeFormatter.ISO_OFFSET_DATE_TIME);
使用 @JsonDeserialize(using = CustomDeserializer.class)
修饰属性。
@JsonRootName
public record Cargo(String name, BigDecimal weight) {}
// 默认的序列化结果
{"name":"banana","weight":1}
@JsonRootName
注解可使用类名或 value
值作为键值包裹这个结果。
@JsonRootName("_cargo")
public record Cargo(String name, BigDecimal weight) {}
// get
{"_cargo":{"name":"banana","weight":1}}
需要 Mapper 开启 (UN)WRAP_ROOT_VALUE
特性。
mapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
mapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE);
@JsonUnwrapped
与 @JsonRootName
相反,该注解修饰的属性类可以被 flattened。
public class UnwrappedUser {
public int id;
@JsonUnwrapped
public Name name;
public static class Name {
public String firstName;
public String lastName;
// get
{"id":1,"firstName":"John","lastName":"Doe"}
@JsonRawValue
在序列化过程中按原始值输出。
public class RawEntity {
@JsonRawValue
private String raw = "{\"name\":\"John Doe\"}";
// get
{"raw":{"name":"John Doe"}}
public class Zoo {
public Animal animal;
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = As.PROPERTY,
property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = Dog.class, name = "dog"),
@JsonSubTypes.Type(value = Cat.class, name = "cat")
public static class Animal {
public String name;
@JsonTypeName("dog")
public static class Dog extends Animal {
public double barkVolume;
@JsonTypeName("cat")
public static class Cat extends Animal {
boolean likesCream;
public int lives;
建造者模式
建造者模式可以用来一步步构造复杂的对象,此时对象的序列化和反序列化需要配合使用 @JsonPOJOBuilder
和 @JsonDeserialize
。
@JsonDeserialize(builder = Person.Builder.class)
public class Person {
private final String name;
private final Integer age;
private Person(String name, Integer age) {
this.name = name;
this.age = age;
@JsonPOJOBuilder
static class Builder {
String name;
Integer age;
Builder withName(String name) {
this.name = name;
return this;
Builder withAge(Integer age) {
this.age = age;
return this;
public Person build() {
return new Person(name, age);
如果 Builder
中没有使用 withXXX
和 build
方法赋值和构建对象,需要为 @JsonPOJOBuilde
注解指明 buildMethodName
和 withPrefix
。
@JsonPOJOBuilder(buildMethodName = "create", withPrefix = "set")
static class Builder {
String name;
Integer age;
Builder setName(String name) {
this.name = name;
return this;
Builder setAge(Integer age) {
this.age = age;
return this;