框架简介

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。JsonFactoryJsonParserJsonGenerator
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

使用的Demo:https://gitee.com/li_kun_zang/jackson-demo/blob/main/core/src/main/java/com/zanglikun/JacksonCoreDemo.java

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

特殊说明:
上述文章均是作者实际操作后产出。烦请各位,请勿直接盗用!转载记得标注原文链接:www.zanglikun.com
第三方平台不会及时更新本文最新内容。如果发现本文资料不全,可访问本人的Java博客搜索:标题关键字。以获取最新全部资料 ❤

免责声明:
本站文章旨在总结学习互联网技术过程中的经验与见解。任何人不得将其用于违法或违规活动!所有违规内容均由个人自行承担,与作者无关。