Jackson处理JSON和Java对象转换

Jackson 是 Java 处理 JSON 最快的库,比 Gson 快、比 Json-lib 快十倍。核心是 ObjectMapper,转 JSON 用 writeValueAsString,转对象用 readValue,泛型要用 TypeReference 或 JavaType。注意 ObjectMapper 要复用。

Jackson 是 Java 生态里处理 JSON 最流行、最快的库。比 Gson 更快、比 Json-lib 快十倍,而且内置了很多贴心的特性。

为什么选 Jackson

简单对比一下三大 JSON 库:

库 速度 内存占用 易用度 第三方支持
Jackson ⭐⭐⭐⭐⭐ 低 ⭐⭐⭐⭐ 最好(Spring 内置)
Gson ⭐⭐⭐⭐ 中等 ⭐⭐⭐⭐⭐ 很好
Json-lib ⭐⭐ 高 ⭐⭐⭐ 一般

Jackson 的杀手锏是速度和 Spring 生态集成(Spring 默认就用 Jackson)。如果你用 Spring Boot,Jackson 已经帮你包括好了。

核心类:ObjectMapper

ObjectMapper 是 Jackson 的门面类,所有 JSON 操作都通过它。

import com.fasterxml.jackson.databind.ObjectMapper;

ObjectMapper mapper = new ObjectMapper();
​

重要:ObjectMapper 是线程安全的,而且构造很昂贵(内部初始化了各种序列化器)。千万别每次用都 new 一个新的,应该全局复用。

// ❌ 不要这样
public void processJson(String json) {
    ObjectMapper mapper = new ObjectMapper();  // 每次都 new,浪费
    User user = mapper.readValue(json, User.class);
}

// ✅ 应该这样
private static final ObjectMapper mapper = new ObjectMapper();

public void processJson(String json) {
    User user = mapper.readValue(json, User.class);  // 复用同一个实例
}
​

基础用法:对象转 JSON

writeValueAsString:对象转 JSON 字符串

public class User {
    public String name;
    public int age;
  
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

ObjectMapper mapper = new ObjectMapper();
User user = new User("Alice", 30);
String json = mapper.writeValueAsString(user);
System.out.println(json);  // {"name":"Alice","age":30}
​

writeValueAsBytes:对象转 JSON 字节数组

byte[] jsonBytes = mapper.writeValueAsBytes(user);
// 直接写文件或网络流效率更高
​

基础用法:JSON 转对象

readValue:JSON 字符串转对象

String json = "{\"name\":\"Bob\",\"age\":25}";
User user = mapper.readValue(json, User.class);
System.out.println(user.name);  // Bob
System.out.println(user.age);   // 25
​

readValue:从文件/流读取

// 从文件读
User user = mapper.readValue(new File("user.json"), User.class);

// 从输入流读
User user = mapper.readValue(inputStream, User.class);

// 从字节数组读
User user = mapper.readValue(jsonBytes, User.class);
​

处理泛型和集合

情况一:转 List

readValue 的第二个参数只能接收具体的 Class 对象,无法直接表示 List<User> 这种泛型。

// ❌ 这样不行,编译时 List<User>.class 无法取得
List<User> users = mapper.readValue(json, List<User>.class);

// ✅ 用 TypeReference
String json = "[{\"name\":\"Alice\",\"age\":30},{\"name\":\"Bob\",\"age\":25}]";
List<User> users = mapper.readValue(json, new TypeReference<List<User>>(){});
​

TypeReference 是一个抽象类,你 new 一个匿名内部类,Jackson 会通过反射获取泛型信息。看起来有点奇怪,但这是 Java 泛型擦除后绕过的标准方式。

情况二:转 Map

// 转 Map<String, Object>
String json = "{\"name\":\"Alice\",\"age\":30}";
Map<String, Object> map = mapper.readValue(json, new TypeReference<Map<String, Object>>(){});

// 或者用工厂方法
Map<String, Object> map = mapper.readValue(json, Map.class);  // 简单用法
​

情况三:用 JavaType(更灵活)

TypeReference 有时候用着不舒服(比如泛型参数是动态的),可以用 JavaType。

ObjectMapper mapper = new ObjectMapper();

// 构造 List<User> 的 JavaType
JavaType listType = mapper.getTypeFactory()
    .constructParametricType(List.class, User.class);

List<User> users = mapper.readValue(json, listType);

// 或者 Map<String, User>
JavaType mapType = mapper.getTypeFactory()
    .constructMapType(Map.class, String.class, User.class);

Map<String, User> userMap = mapper.readValue(json, mapType);
​

配置和自定义

忽略未知字段

JSON 里有一些 Java 对象里没有的字段,默认会抛异常。

// ❌ 默认行为
String json = "{\"name\":\"Alice\",\"age\":30,\"city\":\"Beijing\"}";
User user = mapper.readValue(json, User.class);  // 报错,因为 User 没有 city 字段

// ✅ 配置忽略
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
User user = mapper.readValue(json, User.class);  // OK,city 字段被忽略
​

自定义字段名映射

用 @JsonProperty 注解指定 JSON 里的字段名。

public class User {
    @JsonProperty("user_name")  // JSON 里叫 user_name
    public String name;
  
    @JsonProperty("user_age")  // JSON 里叫 user_age
    public int age;
}

String json = "{\"user_name\":\"Alice\",\"user_age\":30}";
User user = mapper.readValue(json, User.class);
​

忽略某些字段

public class User {
    public String name;
  
    @JsonIgnore  // 转 JSON 时不包含这个字段
    public int age;
}

User user = new User("Alice", 30);
String json = mapper.writeValueAsString(user);
System.out.println(json);  // {"name":"Alice"}  age 被忽略了
​

使用 snake_case

默认 Jackson 用驼峰命名,如果 JSON 用 snake_case(蛇形命名),可以配置:

mapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);

public class User {
    public String firstName;  // Java 里是 firstName
    public String lastName;
}

// 转 JSON 时会变成 first_name、last_name
String json = mapper.writeValueAsString(user);
// {"first_name":"...","last_name":"..."}
​

常见坑

坑一:ObjectMapper 不是线程安全的吗

ObjectMapper 本身是线程安全的,但配置 ObjectMapper 的时候(比如调 disable/enable)不是线程安全的。

// ❌ 在多线程环境下边用边改配置
if (someCondition) {
    mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
}
User user = mapper.readValue(json, User.class);

// ✅ 应该在初始化时一次性配置好
private static final ObjectMapper mapper = initMapper();

private static ObjectMapper initMapper() {
    ObjectMapper m = new ObjectMapper();
    m.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
    return m;
}
​

坑二:泛型擦除导致的类型丢失

// ❌ 编译期泛型,运行期消失
Class<?> clazz = List.class;  // 只是 List,看不到 <User>

// ✅ 用 TypeReference 或 JavaType 保留泛型信息
JavaType type = mapper.getTypeFactory()
    .constructParametricType(List.class, User.class);
​

坑三:JSON 里有 null 值的处理

// 默认 null 值会被保留
String json = "{\"name\":\"Alice\",\"age\":null}";
User user = mapper.readValue(json, User.class);
System.out.println(user.age);  // 0(基本类型 int 的默认值)

// 如果用 Integer 就能区分 null 和 0
public class User {
    public String name;
    public Integer age;  // 包装类
}

user = mapper.readValue(json, User.class);
System.out.println(user.age);  // null
​

坑四:枚举序列化

public enum Status {
    ACTIVE, INACTIVE
}

public class Task {
    public Status status;
}

// 默认序列化为字符串
Task task = new Task();
task.status = Status.ACTIVE;
String json = mapper.writeValueAsString(task);
System.out.println(json);  // {"status":"ACTIVE"}

// 反序列化也会按名称匹配
String json = "{\"status\":\"INACTIVE\"}";
Task task = mapper.readValue(json, Task.class);
System.out.println(task.status);  // Status.INACTIVE
​

性能建议

// ✅ 好的做法
private static final ObjectMapper mapper = new ObjectMapper();
private static final JavaType userListType = mapper.getTypeFactory()
    .constructParametricType(List.class, User.class);

public List<User> deserializeUsers(String json) {
    return mapper.readValue(json, userListType);  // 复用 mapper 和 type
}

// ❌ 不好的做法
public List<User> deserializeUsers(String json) {
    ObjectMapper mapper = new ObjectMapper();  // 每次都 new
    return mapper.readValue(json, new TypeReference<List<User>>(){});  // 每次都创建
}
​

小结

Jackson 是 Java 处理 JSON 的最优选择。核心要点:

  • ObjectMapper 全局复用,不要每次 new
  • 对象转 JSON 用 writeValueAsString
  • JSON 转对象用 readValue
  • 处理泛型用 TypeReference 或 JavaType
  • 提前配置好 ObjectMapper,别在使用时动态改

掌握这些,Jackson 就能被用好。

更多推荐

章节目录