Jackson 详细教程:Java 中最好用的 JSON 处理库之一
在 Java 开发里,只要你要和前端、接口、微服务打交道,就几乎绕不开 JSON 。
而在 Java 生态中,最常用的 JSON 处理库之一就是 Jackson。
很多人一开始对 Jackson 的印象只是:
ObjectMapperwriteValueAsString()readValue()
但实际上,Jackson 不只是"对象转 JSON"这么简单,它还可以做:
- Java 对象和 JSON 字符串互转
- 集合、泛型、Map 的转换
- 日期格式处理
- 忽略字段、重命名字段
- 空值处理
- 枚举处理
- 自定义序列化和反序列化
- 与 Spring Boot 自动集成
这篇文章会系统地把 Jackson 讲清楚。
一、什么是 Jackson
Jackson 是 Java 里一个非常流行的 JSON 处理框架,核心作用是:
- 序列化:把 Java 对象转成 JSON
- 反序列化:把 JSON 转成 Java 对象
比如:
java
User user = new User("张三", 18);
可以转成:
java
{"name":"张三","age":18}
也可以把上面的 JSON 再转回 User 对象。
二、为什么要学 Jackson
因为它在 Java 后端里出现得太频繁了:
- Spring Boot 默认就集成了 Jackson
- 接口返回 JSON 时底层常常就是 Jackson 在处理
@RequestBody、@ResponseBody的很多 JSON 映射背后也是它- 面试里经常会问:
ObjectMapper是什么@JsonIgnore有什么用- 如何处理日期格式
- 如何处理泛型集合
- 如何自定义 JSON 字段名
所以 Jackson 不只是一个工具类,而是后端接口开发的基础能力。
三、Jackson 的核心类
学习 Jackson,先记住这几个核心类。
1. ObjectMapper
这是最核心的类,几乎所有常用操作都围绕它展开。
它可以做:
- Java 对象转 JSON 字符串
- JSON 字符串转 Java 对象
- JSON 转 Map
- JSON 转集合
- 配置序列化和反序列化规则
示例:
java
ObjectMapper objectMapper = new ObjectMapper();
2. JsonNode
如果你不想立刻转成某个 Java 类,也可以先把 JSON 读成树结构,再按节点读取。
适合:
- JSON 结构不固定
- 只想临时取某个字段
- 动态解析
3. TypeReference
Jackson 处理泛型时非常重要。
比如:
java
List<User>
Map<String, User>
Result<User>
这些带泛型的类型,直接用 Class 不够,需要 TypeReference。
四、先引入依赖
如果你是 Maven 项目:
java
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.17.0</version>
</dependency>
</dependencies>
如果你是 Spring Boot 项目,通常已经自动带上 Jackson 了,一般不用单独加。
五、最基础的用法
1. Java 对象转 JSON
先定义一个实体类:
java
public class User {
private String name;
private Integer age;
public User() {
}
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public Integer getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
}
然后序列化:
ObjectMapper objectMapper = new ObjectMapper();
User user = new User("张三", 18);
String json = objectMapper.writeValueAsString(user);
System.out.println(json);
输出:
{"name":"张三","age":18}
这里的 writeValueAsString() 就是:
把 Java 对象写成 JSON 字符串。
2. JSON 转 Java 对象
java
ObjectMapper objectMapper = new ObjectMapper();
String json = "{\"name\":\"李四\",\"age\":20}";
User user = objectMapper.readValue(json, User.class);
System.out.println(user.getName());
System.out.println(user.getAge());
输出:
李四
20
这里的 readValue() 就是:
把 JSON 字符串读取成 Java 对象。
六、集合和 Map 的处理
很多初学者只会转普通对象,但项目里更常见的是:
List<User>Map<String, Object>Result<User>
1. List 转 JSON
java
List<User> list = new ArrayList<>();
list.add(new User("张三", 18));
list.add(new User("李四", 20));
ObjectMapper objectMapper = new ObjectMapper();
String json = objectMapper.writeValueAsString(list);
System.out.println(json);
输出:
{"name":"张三","age":18},{"name":"李四","age":20}
2. JSON 转 List
这个地方必须注意:
不能简单写成 List.class,否则元素会变成 LinkedHashMap。
正确写法:
java
String json = "[{\"name\":\"张三\",\"age\":18},{\"name\":\"李四\",\"age\":20}]";
ObjectMapper objectMapper = new ObjectMapper();
List<User> users = objectMapper.readValue(
json,
new TypeReference<List<User>>() {}
);
for (User user : users) {
System.out.println(user.getName() + " - " + user.getAge());
}
这里的重点是:
new TypeReference<List<User>>() {}
因为 Java 泛型有类型擦除,Jackson 需要你显式告诉它完整类型。
3. JSON 转 Map
java
String json = "{\"name\":\"张三\",\"age\":18}";
ObjectMapper objectMapper = new ObjectMapper();
Map<String, Object> map = objectMapper.readValue(
json,
new TypeReference<Map<String, Object>>() {}
);
System.out.println(map.get("name"));
System.out.println(map.get("age"));
七、常用注解详解
Jackson 之所以强大,一个重要原因就是有很多注解。
1. @JsonIgnore
忽略某个字段,不参与 JSON 序列化或反序列化。
java
public class User {
private String name;
@JsonIgnore
private String password;
private Integer age;
// getter/setter
}
对象转 JSON 时:
{"name":"张三","age":18}
password 不会输出。
适用场景:
- 密码
- 敏感信息
- 内部字段
2. @JsonProperty
给 JSON 字段改名字。
java
public class User {
@JsonProperty("user_name")
private String name;
private Integer age;
// getter/setter
}
输出:
{"user_name":"张三","age":18}
适用场景:
- Java 字段名和前端字段名不一致
- 接第三方接口时字段名有特殊格式
3. @JsonFormat
常用来格式化日期。
java
public class User {
private String name;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
// getter/setter
}
输出:
{"name":"张三","createTime":"2025-03-08 14:30:00"}
4. @JsonInclude
控制空值字段是否输出。
java
@JsonInclude(JsonInclude.Include.NON_NULL)
public class User {
private String name;
private Integer age;
private String email;
// getter/setter
}
如果 email = null,序列化时就不会输出 email。
5. @JsonAlias
反序列化时支持别名。
java
public class User {
@JsonAlias({"userName", "username"})
private String name;
private Integer age;
// getter/setter
}
那么这两种 JSON 都能识别:
{"userName":"张三","age":18}
{"username":"张三","age":18}
6. @JsonIgnoreProperties
忽略未知字段,防止反序列化报错。
java
@JsonIgnoreProperties(ignoreUnknown = true)
public class User {
private String name;
private Integer age;
// getter/setter
}
如果 JSON 多了别的字段,比如:
{"name":"张三","age":18,"address":"北京"}
也不会报错。
八、空值、未知字段、日期的常见配置
这些在项目里特别常用。
1. 忽略空值字段
java
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
这样所有 null 字段默认不输出。
2. 忽略未知字段
java
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
当 JSON 中字段比 Java 类多时,不报错。
3. 日期格式化
java
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
4. 美化输出
java
String json = objectMapper
.writerWithDefaultPrettyPrinter()
.writeValueAsString(user);
输出更好看:
{
"name" : "张三",
"age" : 18
}
适合日志、调试、学习。
九、JsonNode 的用法
如果 JSON 结构复杂,或者你只想取部分字段,可以用 JsonNode。
java
String json = "{\"name\":\"张三\",\"age\":18,\"address\":{\"city\":\"北京\"}}";
ObjectMapper objectMapper = new ObjectMapper();
JsonNode root = objectMapper.readTree(json);
String name = root.get("name").asText();
int age = root.get("age").asInt();
String city = root.get("address").get("city").asText();
System.out.println(name);
System.out.println(age);
System.out.println(city);
适用场景:
- 第三方接口返回格式复杂
- 字段不固定
- 只取某几个值,不想专门建类
十、泛型对象怎么处理
很多项目都有统一返回对象,比如:
java
public class Result<T> {
private Integer code;
private String message;
private T data;
public Result() {
}
public Result(Integer code, String message, T data) {
this.code = code;
this.message = message;
this.data = data;
}
// getter/setter
}
如果 JSON 是:
{
"code": 200,
"message": "success",
"data": {
"name": "张三",
"age": 18
}
}
要转成 Result<User>:
java
String json = "{\"code\":200,\"message\":\"success\",\"data\":{\"name\":\"张三\",\"age\":18}}";
ObjectMapper objectMapper = new ObjectMapper();
Result<User> result = objectMapper.readValue(
json,
new TypeReference<Result<User>>() {}
);
System.out.println(result.getData().getName());
这里必须使用 TypeReference<Result<User>>() {}。
十一、自定义序列化器和反序列化器
当默认规则不够用时,可以自定义。
1. 自定义序列化器
比如把 Long 类型序列化成字符串,避免前端精度丢失。
java
public class LongToStringSerializer extends JsonSerializer<Long> {
@Override
public void serialize(Long value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeString(String.valueOf(value));
}
}
然后在字段上使用:
java
public class User {
@JsonSerialize(using = LongToStringSerializer.class)
private Long id;
private String name;
// getter/setter
}
这样 id 输出时就是字符串:
{"id":"1234567890123456789","name":"张三"}
2. 自定义反序列化器
比如把 "男"、"女" 转成数字编码。
java
public class GenderDeserializer extends JsonDeserializer<Integer> {
@Override
public Integer deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
String value = p.getText();
if ("男".equals(value)) {
return 1;
}
if ("女".equals(value)) {
return 2;
}
return 0;
}
}
字段上使用:
java
public class User {
private String name;
@JsonDeserialize(using = GenderDeserializer.class)
private Integer gender;
// getter/setter
}
十二、枚举处理
枚举在项目里也经常用。
java
public enum Gender {
MALE,
FEMALE
}
默认会输出枚举名:
{"gender":"MALE"}
如果你想输出更友好的值,可以配合 @JsonValue:
java
public enum Gender {
MALE("男"),
FEMALE("女");
private final String desc;
Gender(String desc) {
this.desc = desc;
}
@JsonValue
public String getDesc() {
return desc;
}
}
输出:
{"gender":"男"}
十三、Spring Boot 中 Jackson 的作用
如果你在用 Spring Boot,其实 Jackson 很多时候已经在帮你工作了。
比如:
java
@RestController
public class UserController {
@GetMapping("/user")
public User getUser() {
return new User("张三", 18);
}
@PostMapping("/save")
public String save(@RequestBody User user) {
return "success";
}
}
这里底层发生了两件事:
1. 返回对象时
Spring Boot 会自动把 User 对象转成 JSON 返回给前端。
这个过程通常就是 Jackson 做的。
2. 接收 @RequestBody 时
前端传来的 JSON 会自动转成 User 对象。
这个过程也是 Jackson 做的。
所以你虽然没直接写 ObjectMapper,但你其实已经在用 Jackson。
十四、Spring Boot 中全局配置 Jackson
可以在 application.yml 中做一些简单配置:
java
spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
default-property-inclusion: non_null
作用:
- 日期格式统一
- 时区统一
- 不输出 null 字段
如果要更复杂的配置,可以自己写配置类:
java
@Configuration
public class JacksonConfig {
@Bean
public ObjectMapper objectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
return objectMapper;
}
}
十五、项目中最常见的 Jackson 场景
1. 接口统一返回格式
比如你写全局返回包装:
return Result.success(body);
最后返回给前端时,Jackson 会把它转成 JSON。
2. 处理 String 特殊返回
在 ResponseBodyAdvice 中,如果返回的是 String,经常会手动写:
return objectMapper.writeValueAsString(Result.success(body));
因为 String 类型在 Spring 里走的是特殊转换器。
3. 日志打印对象
很多人喜欢在调试时打印对象 JSON:
System.out.println(objectMapper.writeValueAsString(user));
比直接打印对象更直观。
4. 第三方接口请求与响应
比如你调用外部接口,收到 JSON 字符串后:
Result<User> result = objectMapper.readValue(json, new TypeReference<Result<User>>() {});
十六、Jackson 常见坑
这一部分非常重要。
1. 没有无参构造器
反序列化时,Jackson 往往需要创建对象。
如果类没有无参构造器,可能会失败。
建议:
- 实体类尽量提供无参构造器
- 或者使用 Lombok 的
@NoArgsConstructor
2. 字段没有 getter/setter
Jackson 默认常依赖 getter/setter。
建议实体类规范写好访问器方法。
3. 泛型集合反序列化错误
错误写法:
List<User> users = objectMapper.readValue(json, List.class);
这样会得到 List<LinkedHashMap>,不是 List<User>。
正确写法:
List<User> users = objectMapper.readValue(json, new TypeReference<List<User>>() {});
4. 日期格式不对
如果不配置格式,默认日期输出可能不是你想要的。
解决方式:
- 字段上
@JsonFormat - 全局配置日期格式
5. Long 精度问题
前端 JavaScript 对超大整数有精度限制。
如果后端返回很大的 Long,前端可能丢精度。
解决方式:
- 把
Long序列化成字符串 - 用自定义序列化器
6. String 返回值包装问题
在 Spring 的全局响应处理中,如果遇到:
public String hello() {
return "ok";
}
直接包装成对象可能报错,需要:
objectMapper.writeValueAsString(Result.success(body))
这是 Jackson 在 Spring 项目中最常见的实战坑之一。
十七、Jackson 和 Gson 有什么区别
很多人会把 Jackson 和 Gson 放一起比较。
简单说:
Jackson
- 性能通常不错
- 功能强大
- 注解丰富
- Spring Boot 默认集成
- 企业项目中更常见
Gson
- API 简单
- 上手容易
- 小项目中也常见
如果你是做 Java 后端,尤其是 Spring Boot,
建议重点掌握 Jackson。
十八、学习 Jackson 的建议路线
如果你是初学者,可以按这个顺序学:
第一阶段:核心 API
先掌握:
ObjectMapperwriteValueAsString()readValue()TypeReference
第二阶段:常用注解
重点学:
@JsonIgnore@JsonProperty@JsonFormat@JsonInclude@JsonIgnoreProperties
第三阶段:Spring Boot 集成
搞懂:
@RequestBody@ResponseBody- 为什么 Controller 返回对象会自动变 JSON
ResponseBodyAdvice里和 Jackson 的关系
第四阶段:进阶
学习:
JsonNode- 自定义序列化器
- 自定义反序列化器
- 全局 Jackson 配置
- 枚举和日期处理
十九、实战案例:完整演示
下面给一个更贴近项目的例子。
1. 返回对象
java
public class Result<T> {
private Integer code;
private String message;
private T data;
public Result() {
}
public Result(Integer code, String message, T data) {
this.code = code;
this.message = message;
this.data = data;
}
public static <T> Result<T> success(T data) {
return new Result<>(200, "success", data);
}
public Integer getCode() {
return code;
}
public String getMessage() {
return message;
}
public T getData() {
return data;
}
public void setCode(Integer code) {
this.code = code;
}
public void setMessage(String message) {
this.message = message;
}
public void setData(T data) {
this.data = data;
}
}
2. 用户类
java
@JsonInclude(JsonInclude.Include.NON_NULL)
public class User {
private Long id;
@JsonProperty("user_name")
private String name;
private Integer age;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
@JsonIgnore
private String password;
public User() {
}
public User(Long id, String name, Integer age, Date createTime, String password) {
this.id = id;
this.name = name;
this.age = age;
this.createTime = createTime;
this.password = password;
}
// getter/setter
}
3. 测试序列化
java
public class JacksonDemo {
public static void main(String[] args) throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
User user = new User(1L, "张三", 18, new Date(), "123456");
String json = objectMapper.writeValueAsString(Result.success(user));
System.out.println(json);
}
}
可能输出:
{"code":200,"message":"success","data":{"id":1,"user_name":"张三","age":18,"createTime":"2025-03-08 20:30:00"}}
你会发现:
password被忽略了name变成了user_name- 日期格式化了
- 外层统一包装成了
Result
这就是 Jackson 在实际项目中的典型样子。
二十、总结
Jackson 是 Java 后端开发里非常重要的基础库。
你至少要掌握这几个点:
必会
ObjectMapperwriteValueAsString()readValue()TypeReference
常用注解
@JsonIgnore@JsonProperty@JsonFormat@JsonInclude
实战重点
- List、Map、泛型对象的转换
- Spring Boot 自动 JSON 映射
String返回值特殊处理- 日期与 Long 精度问题
- 自定义序列化和反序列化
一句话总结:
Jackson 不只是"对象转 JSON"的工具,它是 Java 后端和 JSON 世界沟通的核心桥梁。