
框架简介
Jackson 是一个 Java 的 JSON 处理库(也支持 XML、YAML 等),由 FasterXML 开发,在 Java 领域非常流行,用于对象与 JSON 之间的序列化(Java 转 JSON)和反序列化(JSON 转 Java)。
它追求:
- 性能高(比 GSON、org.json 更快)
- 功能丰富(支持大量配置、注解、自定义序列化)
- 生态完善(各种数据格式模块,如 XML、CBOR、Smile)
在国内外的大多数 Spring Boot 项目中,Jackson 是 JSON 的默认处理器。
核心模块
Jackson 由 三大核心组件 构成:
| 模块 | 主要作用 | 常用类 |
|---|---|---|
| Streaming API | 基于事件的、低内存占用的 JSON 解析和生成。适合处理超大 JSON。 | JsonFactory、JsonParser、JsonGenerator |
| Databind | 把 JSON 直接映射成 Java 对象,或反之。集成了 Streaming API,但更易用。 | ObjectMapper(最常用) |
| Annotations | 用注解定制序列化/反序列化行为。 | @JsonProperty、@JsonIgnoreProperties、@JsonFormat |
在实际开发中,我们大多数时间直接用 Databind + 注解。
Jackson官网
https://github.com/FasterXML/jackson
相关注解
| 注解 | 作用 | 使用位置 | 示例 |
|---|---|---|---|
@JsonProperty | 指定 JSON 中的字段名,或控制序列化/反序列化访问 | 字段 / getter / setter | @JsonProperty("user_name") private String name; |
@JsonIgnore | 忽略该字段的序列化与反序列化 | 字段 / getter / setter | @JsonIgnore private String password; |
@JsonIgnoreProperties | 忽略多个字段,或忽略 JSON 中未知字段 | 类 | @JsonIgnoreProperties({"password", "salt"}) |
@JsonFormat | 格式化日期时间,指定时区 | 字段 | @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone="GMT+8") private Date createTime; |
@JsonInclude | 控制 null / 空值字段是否输出 | 类 / 字段 | @JsonInclude(JsonInclude.Include.NON_NULL) |
@JsonCreator | 自定义反序列化时的构造方法或工厂方法 | 构造方法 / 静态方法 | @JsonCreator public User(@JsonProperty("name") String name) {...} |
@JsonDeserialize | 指定自定义反序列化器 | 字段 / 类 | @JsonDeserialize(using = CustomDateDeserializer.class) |
@JsonSerialize | 指定自定义序列化器 | 字段 / 类 | @JsonSerialize(using = CustomDateSerializer.class) |
@JsonSetter | 给 JSON 字段绑定特定的 setter 方法名 | Setter 方法 | @JsonSetter("user_name") public void setName(String name) {...} |
@JsonAnySetter | 捕获 JSON 中所有未知属性并存入 Map | 方法 | @JsonAnySetter public void set(String key, Object value){ ... } |
@JsonAnyGetter | 将 Map 中的字段序列化为 JSON 根级字段 | 方法 | @JsonAnyGetter public Map<String,Object> getProps(){ ... } |
注解使用(Databind + 注解)
1、定义
import com.fasterxml.jackson.annotation.*;
import java.util.Date;
import java.util.Map;
@JsonIgnoreProperties(ignoreUnknown = true) // 忽略未知字段
@JsonInclude(JsonInclude.Include.NON_NULL) // 不输出 null 值
public class User {
@JsonProperty("user_name") // 映射字段名
private String name;
@JsonIgnore // 完全忽略
private String password;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
private Map<String, Object> extra;
@JsonAnySetter // 接收未知字段
public void setExtra(String key, Object value) {
if (extra != null) {
extra.put(key, value);
}
}
// Getter / Setter 省略
}
2、使用
import com.fasterxml.jackson.databind.ObjectMapper;
import java.text.SimpleDateFormat;
import java.util.Date;
public class JacksonTest {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
// 忽略出现未知字段报错
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// 设置解析字段最大的长度。默认Jackson是2千万。这里设置为近似无限制,防止报错
mapper.getFactory().setStreamReadConstraints(
StreamReadConstraints.builder()
.maxStringLength(Integer.MAX_VALUE)
.build());
// 1. JSON 反序列化(包含未知字段 + null 值)
String jsonInput = "{ \"user_name\":\"Tom\", \"password\":\"secret\", "
+ "\"createTime\":\"2024-06-12 10:30:00\", \"hobby\":\"coding\", \"level\":5 }";
User user = mapper.readValue(jsonInput, User.class);
System.out.println("反序列化结果:" + user);
// 2. 序列化 (密码被忽略,未知字段保留在 extra 中)
user.setCreateTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2024-06-12 10:30:00"));
String jsonOutput = mapper.writeValueAsString(user);
System.out.println("序列化结果:" + jsonOutput);
// 3. 忽略 null 字段
User nullFieldUser = new User();
nullFieldUser.setName("Jack");
nullFieldUser.setCreateTime(new Date());
System.out.println("忽略 null 字段:" + mapper.writeValueAsString(nullFieldUser));
}
}
更多案例说明
代码仓库见于:https://gitee.com/li_kun_zang/jackson-demo
jacksonConfig:https://gitee.com/li_kun_zang/jackson-demo/blob/main/spring-boot/src/main/java/com/zanglikun/config/JacksonConfig.java
自定义序列化、反序列化:https://gitee.com/li_kun_zang/jackson-demo/tree/main/core/src/main/java/com/zanglikun
常见异常说明
InvalidDefinitionException
com.fasterxml.jackson.databind.exc.InvalidDefinitionException:
Cannot construct instance of `com.example.dto.SOMEEntity$TableDataItem`:
non-static inner classes like this can only be instantiated using default, no-argument constructor
Jackson 反序列化时是通过反射调用无参构造器来创建对象的。
因为非静态内部类的创建,都需要依赖外部类来创建。如:
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner(); // 必须依赖 outer 实例
解决办法
办法1:改为静态内部类(推荐)
public static class TableDataItem {
// 字段、Getter/Setter ...
}
办法2:改为顶层类
把内部类提到外面(同一个包内),让它变成一个单独的 public class。
UnrecognizedPropertyException
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException:
Unrecognized field "archObjId"
(class com.example.dto.SOMEEntity$TableDataItem),
not marked as ignorable (one known property: "staticsInfos"])
Jackson 在反序列化的时候,发现 JSON 里面多了 archObjId 这样的字段,而你的 TableDataItem 类上并没有对应的属性,也没有告诉 Jackson “可以忽略未知字段”,所以就抛了:
Jackson 默认是“严格匹配”,任何未在类中声明的字段都会导致异常。
解决办法
办法 1:在类上加忽略未知字段注解 (内部类也需要加)
@JsonIgnoreProperties(ignoreUnknown = true)
办法 2:在 ObjectMapper 上全局配置忽略未知字段
import com.fasterxml.jackson.databind.DeserializationFeature;
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
办法 3:把 JSON 里需要保留的字段在 DTO 中声明出来 (不推荐)
Java对象缺啥字段,补啥字段。
JsonMappingException 超长Jackson 安全限制
com.fasterxml.jackson.databind.JsonMappingException:
String length (20054016) exceeds the maximum length (20000000)
(through reference chain: java.util.ArrayList[37] -> com.example.dto.SomeEntity["CHANGE_DETAILS"])
这个字段对应的字符串太长了,超过了 Jackson 允许的最大字符串长度(默认值是 20,000,000 字符)
解决方案
方案 1:调整 Jackson 最大字符串长度限制 Jackson 2.15+
ObjectMapper mapper = new ObjectMapper();
mapper.getFactory().setStreamReadConstraints(
StreamReadConstraints.builder()
.maxStringLength(Integer.MAX_VALUE) // 或者设置更合理的上限
.build()
);
方案2:业务截断超长字符!或者升级到Jackson2.15
第三方平台不会及时更新本文最新内容。如果发现本文资料不全,可访问本人的Java博客搜索:标题关键字。以获取最新全部资料 ❤
免责声明: 本站文章旨在总结学习互联网技术过程中的经验与见解。任何人不得将其用于违法或违规活动!所有违规内容均由个人自行承担,与作者无关。
