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 就能被用好。
