序列化 之 Jackson(一)概要

Jackson 是 Java 生态中最流行、高性能的 JSON 处理库,由 FasterXML 维护。它不仅支持 JSON 与 Java 对象之间的双向转换(序列化/反序列化),还支持 XML、YAML、CSV 等多种数据格式。下面从核心原理详细使用示例两方面深入解析。


一、Jackson 核心原理

1. 三大核心模块

模块 Maven 坐标 功能
jackson-core com.fasterxml.jackson.core:jackson-core 底层流式 API(JsonParser / JsonGenerator),提供高性能读写能力
jackson-databind com.fasterxml.jackson.core:jackson-databind 高层数据绑定 API(ObjectMapper),实现 POJO 与 JSON 互转(最常用)
jackson-annotations com.fasterxml.jackson.core:jackson-annotations 注解支持(如 @JsonProperty, @JsonIgnore

✅ Spring Boot 默认集成 Jackson,无需额外引入依赖(除非版本冲突)。


2. 核心组件架构

[Java Object] 
     ⇅ (通过 ObjectMapper)
[Token Stream] ←→ [JSON String]
     ⇅ (通过 JsonParser / JsonGenerator)
[Raw Bytes / Reader / Writer]
  • ObjectMapper:入口类,负责配置、序列化(writeValue)、反序列化(readValue
  • JsonFactory:创建底层 JsonParser(读)和 JsonGenerator(写)
  • JsonParser:将 JSON 字符串解析为 Token 流(如 START_OBJECT, FIELD_NAME, VALUE_STRING...)
  • JsonGenerator:将 Token 流写入目标(String/Stream/File)

💡 性能关键:Jackson 使用 Streaming API + 反射/字节码生成 实现高效转换,避免中间 DOM 树构建(对比 Gson)。


3. 序列化/反序列化流程

序列化(Java → JSON)

  1. ObjectMapper.writeValue() 调用
  2. 通过反射/ASM 获取对象字段/方法
  3. 按注解规则过滤/重命名字段
  4. 生成 Token 流 → 写入 JsonGenerator → 输出 JSON

反序列化(JSON → Java)

  1. ObjectMapper.readValue() 调用
  2. JsonParser 解析 JSON 为 Token 流
  3. 根据目标类型构造对象(调用无参构造 or @JsonCreator
  4. 按字段名匹配 Token 值,通过 setter/字段赋值

二、详细使用示例

示例 1:基础序列化与反序列化

// 定义 POJO
public class User {
    public String name;
    private int age;
    
    // 必须有无参构造(或 @JsonCreator)
    public User() {}
    
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
}

// 使用 ObjectMapper
ObjectMapper mapper = new ObjectMapper();

// 序列化:Java → JSON
User user = new User("Alice", 30);
String json = mapper.writeValueAsString(user);
// 输出: {"name":"Alice","age":30}

// 反序列化:JSON → Java
User newUser = mapper.readValue(json, User.class);

⚠️ 注意:

  • 字段需 public 或提供 getter/setter
  • 必须有 无参构造函数(除非使用 @JsonCreator

示例 2:常用注解控制行为

注解 作用 示例
@JsonProperty 自定义 JSON 字段名 @JsonProperty("user_name") String name;
@JsonIgnore 忽略字段 @JsonIgnore String password;
@JsonFormat 格式化日期/数字 @JsonFormat(pattern="yyyy-MM-dd") Date birth;
@JsonInclude 控制空值输出 @JsonInclude(JsonInclude.Include.NON_NULL)
@JsonCreator 自定义反序列化构造 见下文
public class Product {
    @JsonProperty("product_id")
    private Long id;
    
    @JsonInclude(JsonInclude.Include.NON_EMPTY)
    private String description; // null 或 "" 不输出
    
    @JsonFormat(pattern = "yyyy/MM/dd")
    private Date createTime;
    
    @JsonIgnore
    private String secretKey;
    
    // getter/setter...
}

示例 3:处理复杂场景

场景 1:反序列化时指定构造函数(@JsonCreator

public class Point {
    private final int x, y;
    
    @JsonCreator
    public Point(@JsonProperty("x") int x, @JsonProperty("y") int y) {
        this.x = x;
        this.y = y;
    }
}
// JSON: {"x":10,"y":20} → 正确反序列化

场景 2:泛型反序列化(TypeReference)

List<User> users = mapper.readValue(jsonArray, 
    new TypeReference<List<User>>() {});

场景 3:忽略未知字段(防止反序列化失败)

mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

场景 4:自定义序列化器(Serializer)

public class MoneySerializer extends JsonSerializer<BigDecimal> {
    @Override
    public void serialize(BigDecimal value, JsonGenerator gen, SerializerProvider serializers) 
            throws IOException {
        gen.writeString("$" + value.setScale(2, RoundingMode.HALF_UP).toString());
    }
}

// 使用
public class Order {
    @JsonSerialize(using = MoneySerializer.class)
    private BigDecimal amount;
}

示例 4:全局配置(Spring Boot 中常用)

@Configuration
public class JacksonConfig {
    @Bean
    @Primary
    public ObjectMapper objectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        
        // 忽略未知字段
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        
        // 空对象不抛异常
        mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        
        // 日期格式化
        mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        
        // 属性为 NULL 不序列化
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        
        return mapper;
    }
}

✅ 在 Spring Boot 中,也可通过 application.yml 配置:

spring:
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8
    default-property-inclusion: non_null
    deserialization:
      fail-on-unknown-properties: false

三、高级特性

1. 混合注解(MixIn)

为无法修改的第三方类添加注解行为:

// 为 java.util.Date 添加格式化
public abstract class DateMixin {
    @JsonFormat(pattern = "yyyy-MM-dd")
    public abstract void setDate(Date d);
}

// 注册 MixIn
mapper.addMixIn(Date.class, DateMixin.class);

2. 树模型(JsonNode)

无需 POJO 直接操作 JSON:

JsonNode root = mapper.readTree(json);
String name = root.get("name").asText();
int age = root.get("age").asInt();

3. 流式处理(大文件)

避免内存溢出:

try (JsonParser parser = mapper.createParser(new File("huge.json"))) {
    while (parser.nextToken() != null) {
        // 逐个 Token 处理
    }
}

四、常见问题与最佳实践

问题 解决方案
循环引用 StackOverflow 使用 @JsonIdentityInfo 或 DTO 转换
日期格式混乱 全局配置 setDateFormat() 或字段级 @JsonFormat
反序列化失败(UnknownProperty) 关闭 FAIL_ON_UNKNOWN_PROPERTIES
性能瓶颈 复用 ObjectMapper(线程安全!),避免重复创建
中文乱码 确保输出流编码为 UTF-8(Web 场景通常自动处理)

重要ObjectMapper线程安全 的,应作为单例使用!


五、与其他库对比

特性 Jackson Gson Fastjson
性能 ⭐⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐(但有安全风险)
注解丰富度 极高 中等 中等
Spring Boot 集成 默认 需替换 需替换
安全性 历史漏洞多
流式处理 支持 不支持 支持

📌 结论:在 Spring 生态中,Jackson 是首选


总结

Jackson 的强大在于:

  • 分层设计:Streaming(底层) + Databind(高层) + Annotations(灵活控制)
  • 高性能:基于 Token 流 + 字节码优化
  • 高度可定制:注解、自定义序列化器、MixIn、全局配置

掌握其核心原理和常用注解,能高效解决 99% 的 JSON 处理需求。在微服务、API 开发、配置解析等场景中不可或缺。

posted @ 2026-01-21 19:09  蓝迷梦  阅读(30)  评论(0)    收藏  举报