Jackson怎么用?

wen python案例 2

Jackson深度指南:从入门到精通的全方位解析(2024最新版)

📖 文章目录

  1. Jackson是什么?为什么它是Java开发者的首选JSON库?
  2. Jackson核心模块解析:jackson-core、jackson-databind、jackson-annotations
  3. Jackson基础用法:对象与JSON的互相转换
  4. Jackson高级特性:自定义序列化/反序列化、注解驱动、多态处理
  5. Jackson常见问题与最佳实践(含代码示例)
  6. Jackson与Spring Boot、REST API的集成
  7. 性能优化与避坑指南
  8. FAQ:开发者最常问的10个Jackson问题

Jackson是什么?为什么它是Java开发者的首选JSON库?

问答环节:

Jackson怎么用?

Q:Jackson和其他JSON库(如Gson、Fastjson)相比有什么优势?
A:Jackson是目前Java生态中最成熟、性能最优的JSON处理库之一,它的优势在于:

  • 性能卓越:经过多年优化,序列化/反序列化速度在主流库中排名前列
  • 功能完整:支持流式API、树模型、数据绑定三种处理方式
  • 深度集成:与Spring Boot、JAX-RS等框架无缝对接
  • 社区活跃:GitHub星数超过9k,更新频繁,文档完善

Jackson最初由Fasterxml公司开发,目前是Java JSON处理的事实标准,它能将Java对象(POJO)与JSON字符串相互转换,也能处理XML、YAML、CSV等其他格式。


Jackson核心模块解析

Jackson由三个核心模块组成:

1 jackson-core(基础流API)

提供低级别的JSON流式处理能力,包含JsonParserJsonGenerator,适合处理超大JSON文件,内存占用极低。

<!-- Maven依赖 -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.17.0</version>
</dependency>

2 jackson-databind(数据绑定)

最常用的模块,支持ObjectMapper类,实现对象与JSON的自动映射。

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.17.0</version>
</dependency>

3 jackson-annotations(注解支持)

提供@JsonProperty@JsonIgnore@JsonFormat等注解,控制序列化行为。

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.17.0</version>
</dependency>

最佳实践: 通常只需引入jackson-databind,它会自动依赖其他两个模块。


Jackson基础用法:对象与JSON的互相转换

1 准备工作:创建POJO类

public class User {
    private String name;
    private int age;
    private String email;
    // 必须提供无参构造器和getter/setter
    public User() {}
    // getter/setter省略...
}

2 序列化:Java对象 → JSON字符串

ObjectMapper mapper = new ObjectMapper();
User user = new User("张三", 28, "zhangsan@example.com");
try {
    // 转换为JSON字符串
    String json = mapper.writeValueAsString(user);
    System.out.println(json);
    // 输出:{"name":"张三","age":28,"email":"zhangsan@example.com"}
    // 写入文件
    mapper.writeValue(new File("user.json"), user);
} catch (JsonProcessingException e) {
    e.printStackTrace();
}

3 反序列化:JSON字符串 → Java对象

String jsonInput = "{\"name\":\"李四\",\"age\":30,\"email\":\"lisi@example.com\"}";
try {
    User user = mapper.readValue(jsonInput, User.class);
    System.out.println(user.getName()); // 输出:李四
} catch (JsonProcessingException e) {
    e.printStackTrace();
}

4 处理集合与泛型

// 反序列化List
String jsonArray = "[{\"name\":\"用户1\"},{\"name\":\"用户2\"}]";
List<User> users = mapper.readValue(jsonArray, 
    mapper.getTypeFactory().constructCollectionType(List.class, User.class));
// 反序列化Map
String jsonMap = "{\"key1\":\"value1\",\"key2\":\"value2\"}";
Map<String, String> map = mapper.readValue(jsonMap, 
    mapper.getTypeFactory().constructMapType(Map.class, String.class, String.class));

问答环节:

Q:反序列化时JSON字段名与Java属性名不匹配怎么办?
A:使用@JsonProperty("json_field_name")注解映射字段名,或配置ObjectMapperPropertyNamingStrategy


Jackson高级特性

1 自定义序列化/反序列化

场景: 需要将Date类型格式化为特定格式

// 方式1:使用注解
public class Event {
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date eventDate;
    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
    private Date birthDate;
}
// 方式2:自定义Serializer
public class CustomDateSerializer extends StdSerializer<Date> {
    private static final SimpleDateFormat formatter = 
        new SimpleDateFormat("yyyy/MM/dd");
    public CustomDateSerializer() { super(Date.class); }
    @Override
    public void serialize(Date value, JsonGenerator gen, 
            SerializerProvider provider) throws IOException {
        gen.writeString(formatter.format(value));
    }
}
// 注册到ObjectMapper
SimpleModule module = new SimpleModule();
module.addSerializer(Date.class, new CustomDateSerializer());
mapper.registerModule(module);

2 注解驱动控制

public class Product {
    @JsonProperty("product_id")  // 自定义JSON字段名
    private int id;
    @JsonIgnore  // 忽略该字段
    private String internalCode;
    @JsonInclude(JsonInclude.Include.NON_NULL)  // 空值不序列化
    private String description;
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
    private Date createTime;
    @JsonProperty(access = JsonProperty.Access.READ_ONLY)  // 只读
    private String computedField;
}

3 多态类型处理

当接口或抽象类有多个实现时:

@JsonTypeInfo(
    use = JsonTypeInfo.Id.NAME,
    property = "type"
)
@JsonSubTypes({
    @JsonSubTypes.Type(value = Circle.class, name = "circle"),
    @JsonSubTypes.Type(value = Rectangle.class, name = "rectangle")
})
public abstract class Shape { }
public class Circle extends Shape {
    public double radius;
}
// 反序列化时根据"type"字段自动识别子类
String json = "{\"type\":\"circle\",\"radius\":5.0}";
Shape shape = mapper.readValue(json, Shape.class);
System.out.println(shape instanceof Circle); // true

Jackson常见问题与最佳实践

1 处理未知属性

默认情况下,JSON中存在Java对象没有的字段会抛出异常,推荐配置:

ObjectMapper mapper = new ObjectMapper();
// 忽略未知属性
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// 或者使用注解在类级别
@JsonIgnoreProperties(ignoreUnknown = true)
public class MyClass { }

2 空值处理

// 全局配置:忽略所有null字段
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
// 或者只忽略空集合
mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);

3 日期处理最佳实践

// 禁用时间戳格式,改用字符串格式
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
// 设置全局日期格式
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
mapper.setDateFormat(sdf);

问答环节:

Q:如何避免反序列化时的循环引用问题?
A:使用@JsonIdentityInfo注解或配置SerializationFeature.FAIL_ON_SELF_REFERENCES,更推荐使用DTO模式,只传输必要字段。


Jackson与Spring Boot集成

在Spring Boot中,Jackson已作为默认JSON处理器集成,可通过application.properties配置:

# JSON日期格式
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
# 忽略未知属性
spring.jackson.deserialization.fail-on-unknown-properties=false
# 空值处理
spring.jackson.default-property-inclusion=non_null

自定义ObjectMapper:

@Configuration
public class JacksonConfig {
    @Bean
    @Primary
    public ObjectMapper objectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        // 注册Java8时间模块
        mapper.registerModule(new JavaTimeModule());
        return mapper;
    }
}

在REST Controller中使用:

@RestController
@RequestMapping("/api/users")
public class UserController {
    @PostMapping
    public ResponseEntity<User> createUser(@RequestBody User user) {
        // Jackson自动将JSON反序列化为User对象
        return ResponseEntity.ok(userService.save(user));
    }
    @GetMapping("/{id}")
    public ResponseEntity<User> getUser(@PathVariable Long id) {
        // Jackson自动将User对象序列化为JSON响应
        return ResponseEntity.ok(userService.findById(id));
    }
}

性能优化与避坑指南

1 复用ObjectMapper

错误做法: 每次调用都创建新的ObjectMapper
正确做法: 将ObjectMapper声明为单例或Spring Bean

// 线程安全的,可以全局复用
private static final ObjectMapper MAPPER = new ObjectMapper();

2 使用流式API处理大文件

对于数GB的JSON文件,避免一次性加载:

// 流式解析
try (JsonParser parser = mapper.getFactory().createParser(new File("large.json"))) {
    while (parser.nextToken() != JsonToken.END_OBJECT) {
        String fieldName = parser.getCurrentName();
        parser.nextToken();
        if ("data".equals(fieldName)) {
            // 逐条处理数据
            User user = mapper.readValue(parser, User.class);
        }
    }
}

3 避免使用自动检测

// 禁用自动检测(提升性能)
mapper.configure(MapperFeature.AUTO_DETECT_GETTERS, false);
mapper.configure(MapperFeature.AUTO_DETECT_SETTERS, false);
mapper.configure(MapperFeature.AUTO_DETECT_FIELDS, false);
// 仅通过注解控制序列化
mapper.configure(MapperFeature.USE_ANNOTATIONS, true);

4 常见陷阱

  • 陷阱1: 反序列化时使用内部类(非静态内部类会失败)
  • 陷阱2: 没有无参构造器的类会报错
  • 陷阱3: 日期格式不一致导致解析失败
  • 陷阱4: 高版本Jackson的某些API已废弃(如ObjectMapper.enableDefaultTyping()

FAQ:开发者最常问的10个Jackson问题

问题 解答
Q1:Jackson支持哪些数据格式? 原生支持JSON,通过扩展模块支持XML、YAML、CSV、Properties等
Q2:如何自定义字段命名策略? 使用@JsonProperty或全局配置PropertyNamingStrategy.SNAKE_CASE
Q3:如何处理嵌套对象? 序列化/反序列化自动处理,只需保证嵌套类也有无参构造器
Q4:Jackson与Lombok冲突吗? 不冲突,但需注意Lombok生成的getter/setter名需符合JavaBean规范
Q5:如何序列化枚举? 默认使用枚举名,可通过@JsonFormat(shape = Shape.OBJECT)输出完整对象
Q6:JSONP是什么? Jackson的JSONP支持(JsonpModule),用于处理带回调的JSON
Q7:如何配置最大JSON长度? 通过StreamReadConstraints.builder().maxStringLength(...)
Q8:为什么反序列化时变量为null? 检查setter方法是否存在,或字段是否被@JsonIgnore
Q9:如何实现条件序列化? 使用@JsonView注解,或自定义BeanSerializerModifier
Q10:Jackson 2.x与1.x有什么区别? 包名从org.codehaus.jackson改为com.fasterxml.jackson,API不兼容

Jackson作为Java生态中最强大的JSON处理库,掌握其核心用法和高级特性对于现代Java开发至关重要,从基础的ObjectMapper使用,到自定义序列化、注解驱动控制,再到与Spring Boot的深度集成,Jackson提供了完整的解决方案,记住三个关键点:复用ObjectMapper实例、善用注解配置、注意性能优化陷阱,你就能在实际项目中游刃有余。

如果你刚开始学习,建议从简单的POJO序列化开始,逐步尝试集合处理、日期格式化和自定义序列化,遇到问题时,优先查看Jackson官方文档或GitHub issue区,社区非常活跃,大部分问题都能找到答案。

打开你的IDE,创建一个Maven项目,引入Jackson依赖,开始你的JSON处理之旅吧!

抱歉,评论功能暂时关闭!