替换 FastJSON:推荐 Jackson 及详细用法指南(含工具类 + 替换方案)
文章目录
- 一、推荐替代库:Jackson
- 1、市面上主流JSON 解析库
- 2、为什么选择 Jackson?
- 二、Maven 依赖(Jackson)
- 三、Jackson 常用用法详解
- 1.Java 对象转 JSON 字符串
- 2.JSON 字符串转 Java 对象
- 3.将 JSON 字符串转为 JSON 对象(JsonNode vs ObjectNode)
- (1)JsonNode 与 ObjectNode 的区别
- (2)将 JSON 字符串转为 JsonNode(类似 FastJSON 的 parseObject)
- (3)常用 JsonNode 方法总结
- (4)创建新的 JSON 对象(使用 ObjectNode)
- (5)FastJSON 与 Jackson 对应写法对照表
- (6)总结
- 4.List 转 JSON 数组
- 4.Map 转 JSON
- 5.自定义日期格式
- 6.忽略空字段(NULL 或 EMPTY)
- 四、封装 Jackson 工具类(带注释)
- 五、现有 FastJSON 调用方式一键替换成 Jackson 的写法
- 六、替换步骤建议
- 七、补充建议
- 八、不同项目选择json库总结
FastJSON 曾经是 Java 领域最流行的 JSON 序列化/反序列化库之一,但由于其历史安全问题频发、维护不积极等问题,越来越多公司开始禁用 FastJSON,并转向更稳定、安全、标准的替代库。
本文重点介绍推荐替代 FastJSON 的首选库 —— Jackson,并提供完整的使用示例、封装工具类以及从 FastJSON 迁移至 Jackson 的建议。
一、推荐替代库:Jackson
1、市面上主流JSON 解析库
以下是几个主流的 Java JSON 解析库,适合企业级项目替换使用:
名称 | 优点 | 缺点 | 推荐指数 |
---|---|---|---|
Jackson | 性能好、功能全、社区活跃、Spring Boot 默认使用 | 配置稍复杂,学习曲线略高 | ⭐⭐⭐⭐⭐ |
Gson | Google 出品,简单易用,API 友好 | 性能略逊于 Jackson,不支持流式解析大文件 | ⭐⭐⭐⭐ |
fastjson2(升级版) | FastJSON 官方新版本,修复部分问题 | 社区信任度下降,仍有兼容性/安全性顾虑 | ⭐⭐ |
moshi | 简洁现代,适合 Kotlin 和 Android | 功能较弱,不如 Jackson 强大 | ⭐⭐⭐ |
Yasson / JSON-B | Java EE 标准 JSON 绑定实现 | 使用较少,文档不多 | ⭐⭐ |
2、为什么选择 Jackson?
特性 | 描述 |
---|---|
性能优秀 | 支持流式解析,处理大文件效率高 |
社区活跃 | 官方维护频繁,文档丰富 |
Spring Boot 默认集成 | 几乎所有现代 Spring 项目都基于它 |
安全性更高 | 不像 FastJSON 存在自动类型转换等潜在风险 |
二、Maven 依赖(Jackson)
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.16.1</version>
</dependency>
⚠️ 注意:
jackson-databind
包含了core
和annotations
,一般只需引入此依赖即可。
三、Jackson 常用用法详解
1.Java 对象转 JSON 字符串
//Java 对象转 JSON 字符串@Testpublic void test1() throws JsonProcessingException {ObjectMapper mapper = new ObjectMapper();User user = new User("admin", "若依", 1L);String json = mapper.writeValueAsString(user);System.out.println(json);// 输出: {"username":"admin","nickName":"若依","userId":1}}
2.JSON 字符串转 Java 对象
//JSON 字符串转 Java 对象@Testpublic void test2() throws JsonProcessingException {String json = "{\"username\":\"admin\",\"nickName\":\"若依\",\"userId\":1}";ObjectMapper mapper = new ObjectMapper();User user = mapper.readValue(json, User.class);System.out.println(user.getUsername()); // admin}
3.将 JSON 字符串转为 JSON 对象(JsonNode vs ObjectNode)
在使用 FastJSON 时,我们经常使用如下方式将字符串解析为 JSON 对象:
JSONObject jsonObject = JSON.parseObject(jsonString);
而在 Jackson 中,并没有 JSONObject
这个类,取而代之的是 JsonNode
和 ObjectNode
。理解这两个类的区别和使用方法,对于从 FastJSON 迁移到 Jackson 非常重要。
(1)JsonNode 与 ObjectNode 的区别
类名 | 类型 | 特点 |
---|---|---|
JsonNode | 只读对象 | 是 Jackson 提供的通用 JSON 节点抽象类,可以表示任意 JSON 值(对象、数组、字符串等) |
ObjectNode | 可写对象 | 是 JsonNode 的子类,用于构建或修改 JSON 对象,支持添加字段、嵌套结构等 |
✅ 简单来说:
- 如果你只是想解析并读取 JSON 数据,使用
JsonNode
- 如果你想创建或修改 JSON 内容,使用
ObjectNode
(2)将 JSON 字符串转为 JsonNode(类似 FastJSON 的 parseObject)
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;public class JsonNodeExample {public static void main(String[] args) throws Exception {String jsonStr = "{\n" +" \"username\": \"admin\",\n" +" \"userId\": 1,\n" +" \"dept\": {\n" +" \"deptId\": 103,\n" +" \"deptName\": \"研发部门\"\n" +" },\n" +" \"roles\": [\n" +" {\"roleId\": 1, \"roleName\": \"超级管理员\"},\n" +" {\"roleId\": 2, \"roleName\": \"普通用户\"}\n" +" ]\n" +"}";ObjectMapper mapper = new ObjectMapper();JsonNode rootNode = mapper.readTree(jsonStr);// 获取基本字段String username = rootNode.get("username").asText();int userId = rootNode.get("userId").asInt();// 获取嵌套对象JsonNode deptNode = rootNode.get("dept");String deptName = deptNode.get("deptName").asText();// 获取数组元素JsonNode rolesNode = rootNode.get("roles");for (JsonNode role : rolesNode) {int roleId = role.get("roleId").asInt();String roleName = role.get("roleName").asText();System.out.println("Role ID: " + roleId + ", Name: " + roleName);}}
}
(3)常用 JsonNode 方法总结
方法 | 说明 |
---|---|
get("field") | 获取指定字段的子节点(返回类型为 JsonNode ) |
has("field") | 判断是否存在该字段 |
isValueNode() | 是否是值节点(如字符串、数字等) |
isObject() | 是否是对象节点 |
isArray() | 是否是数组节点 |
isNull() | 是否为 null |
asText() | 转为字符串 |
asInt() / asDouble() / asBoolean() | 转为基础类型 |
size() | 获取数组或对象中字段数量 |
elements() | 获取对象中所有字段的迭代器 |
iterator() | 获取数组中所有元素的迭代器 |
fieldNames() | 获取对象的所有字段名(Iterator) |
(4)创建新的 JSON 对象(使用 ObjectNode)
如果你需要构造一个新的 JSON 对象,而不是仅仅读取已有的 JSON,可以使用 ObjectNode
:
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;public class CreateJsonExample {public static void main(String[] args) {ObjectMapper mapper = new ObjectMapper();ObjectNode userNode = mapper.createObjectNode();userNode.put("username", "admin");userNode.put("userId", 1);userNode.put("status", true);// 添加嵌套对象ObjectNode deptNode = mapper.createObjectNode();deptNode.put("deptId", 103);deptNode.put("deptName", "研发部门");userNode.set("dept", deptNode);// 输出 JSON 字符串System.out.println(userNode.toPrettyString());}
}
输出结果:
{"username" : "admin","userId" : 1,"status" : true,"dept" : {"deptId" : 103,"deptName" : "研发部门"}
}
(5)FastJSON 与 Jackson 对应写法对照表
FastJSON 写法 | Jackson 替代写法 |
---|---|
JSONObject jsonObject = JSON.parseObject(jsonString); | JsonNode jsonNode = objectMapper.readTree(jsonString); |
String name = jsonObject.getString("name"); | String name = jsonNode.get("name").asText(); |
Integer age = jsonObject.getInteger("age"); | int age = jsonNode.get("age").asInt(); |
JSONObject dept = jsonObject.getJSONObject("dept"); | JsonNode dept = jsonNode.get("dept"); |
JSONArray roles = jsonObject.getJSONArray("roles"); | JsonNode roles = jsonNode.get("roles"); |
jsonObject.containsKey("key") | jsonNode.has("key") |
new JSONObject() | ObjectNode objectNode = objectMapper.createObjectNode(); |
jsonObject.put("key", value) | objectNode.put("key", value); |
(6)总结
功能 | 推荐使用类 |
---|---|
解析 JSON 字符串并读取字段 | JsonNode |
构建/修改 JSON 对象 | ObjectNode |
获取字段值 | .get("field").asText() |
判断字段是否存在 | .has("field") |
快速遍历对象字段 | .fieldNames() + 循环 |
快速遍历数组 | for (JsonNode node : arrayNode) |
4.List 转 JSON 数组
@Testpublic void test5() throws JsonProcessingException {List<User> users = Arrays.asList(new User("a", "A", 1), new User("b", "B", 2));ObjectMapper mapper = new ObjectMapper();String jsonArray = mapper.writeValueAsString(users);System.out.println(jsonArray);// [{"username":"a","nickName":"A","userId":1},{"username":"b","nickName":"B","userId":2}]}
4.Map 转 JSON
@Testpublic void test6() throws JsonProcessingException {Map<String, Object> map = new HashMap<>();map.put("name", "admin");map.put("age", 25);ObjectMapper mapper = new ObjectMapper();String json = mapper.writeValueAsString(map);System.out.println(json); // {"name":"admin","age":25}}
5.自定义日期格式
@Testpublic void test7() throws JsonProcessingException {ObjectMapper mapper = new ObjectMapper();mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));User user = new User("admin", "若依", 1L);user.setCreateTime(new Date());String json = mapper.writeValueAsString(user);System.out.println(json);// {"username":"admin","createTime":"2025-05-13 15:00:00"}}
6.忽略空字段(NULL 或 EMPTY)
@Testpublic void test8() throws JsonProcessingException {ObjectMapper mapper = new ObjectMapper();mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); // 忽略 null 字段User user = new User(null, "若依", null);String json = mapper.writeValueAsString(user);System.out.println(json); // {"nickName":"若依"}}
四、封装 Jackson 工具类(带注释)
下面是一个完整的 JsonUtils
工具类,用于统一 JSON 操作入口,便于后续维护和更换底层实现。
package com.wenge.business;import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;import java.util.Collections;
import java.util.List;
import java.util.Map;/*** Jackson JSON 工具类*/
public class JsonUtils {private static final ObjectMapper mapper = new ObjectMapper();static {// 忽略未知字段,防止反序列化失败mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);// 忽略空对象不抛异常mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);// 支持 Java8 时间 API(LocalDate, LocalDateTime)mapper.registerModule(new JavaTimeModule());}/*** 对象转 JSON 字符串*/public static String toJson(Object obj) {try {return mapper.writeValueAsString(obj);} catch (JsonProcessingException e) {throw new RuntimeException("JSON serialize error", e);}}/*** JSON 字符串转 Java 对象*/public static <T> T fromJson(String json, Class<T> clazz) {try {return mapper.readValue(json, clazz);} catch (JsonProcessingException e) {throw new RuntimeException("JSON deserialize error", e);}}/*** JSON 字符串转复杂泛型对象(如 List<User>)*/public static <T> T fromJson(String json, TypeReference<T> typeReference) {try {return mapper.readValue(json, typeReference);} catch (JsonProcessingException e) {throw new RuntimeException("JSON deserialize error", e);}}/*** JSON 转 Map*/public static Map<String, Object> toMap(String json) {if (json == null || json.isEmpty()) {return Collections.emptyMap();}try {return mapper.readValue(json, new TypeReference<Map<String, Object>>() {});} catch (JsonProcessingException e) {throw new RuntimeException("JSON to Map error", e);}}/*** JSON 转 List*/public static <T> List<T> toList(String json, Class<T> elementType) {if (json == null || json.isEmpty()) {return Collections.emptyList();}try {return mapper.readValue(json, mapper.getTypeFactory().constructCollectionType(List.class, elementType));} catch (JsonProcessingException e) {throw new RuntimeException("JSON to List error", e);}}/*** 解析 JSON 字符串为 JsonNode*/public static JsonNode parseTree(String json) {try {return mapper.readTree(json);} catch (JsonProcessingException e) {throw new RuntimeException("JSON parse error", e);}}/*** 创建空的 ObjectNode*/public static ObjectNode createEmptyNode() {return mapper.createObjectNode();}/***解析 JSON 字符串为 ObjectNode**/public static ObjectNode parseObjectNode(String jsonStr, ObjectMapper mapper) throws Exception {JsonNode node = mapper.readTree(jsonStr);if (node.isObject()) {return (ObjectNode) node;} else {throw new IllegalArgumentException("JSON 字符串不是一个对象");}}}
五、现有 FastJSON 调用方式一键替换成 Jackson 的写法
如果你之前使用的是 FastJSON,可以参考以下对应表进行快速替换。
FastJSON 方法 | Jackson 替代方法 | 示例 |
---|---|---|
JSON.toJSONString(obj) | JsonUtils.toJson(obj) | JsonUtils.toJson(user) |
JSON.parseObject(json, User.class) | JsonUtils.fromJson(json, User.class) | JsonUtils.fromJson(json, User.class) |
JSON.parseObject(json, new TypeReference<List<User>>() {}) | JsonUtils.fromJson(json, new TypeReference<List<User>>() {}) | JsonUtils.fromJson(json, new TypeReference<List<User>>() {}) |
JSON.parseObject(json, Map.class) | JsonUtils.toMap(json) | JsonUtils.toMap(json) |
JSON.parseArray(json, User.class) | JsonUtils.toList(json, User.class) | JsonUtils.toList(json, User.class) |
六、替换步骤建议
-
创建
JsonUtils
工具类(见上文) -
全局搜索替换关键字:
JSON.toJSONString(
→JsonUtils.toJson(
JSON.parseObject(
→JsonUtils.fromJson(
new TypeReference<
→new TypeReference<
JSON.parseArray(
→JsonUtils.toList(
-
测试验证:对关键模块进行单元测试或接口测试,确保序列化/反序列化结果一致。
-
逐步上线:先灰度发布部分功能,确认无误后再全面切换。
七、补充建议
建议 | 说明 |
---|---|
✅ 统一 JSON 处理入口 | 使用 JsonUtils 类统一调用,方便后期替换底层库 |
✅ 避免手动拼接 JSON | 易出错且难以维护,应始终使用序列化库生成 JSON |
✅ 开启 Jackson 的严格模式 | 防止非法字段、未知字段导致错误 |
✅ 使用泛型支持复杂结构 | 如 TypeReference 支持嵌套结构、集合类型 |
✅ 日志中打印 JSON 时使用 pretty print | 方便调试,可使用 mapper.writerWithDefaultPrettyPrinter() |
八、不同项目选择json库总结
场景 | 推荐库 |
---|---|
Spring Boot 项目 | ✅ Jackson |
微服务、分布式系统 | ✅ Jackson |
Android / Kotlin 项目 | ✅ Moshi |
简单工具类或小项目 | ✅ Gson |
已有项目迁出 FastJSON | ✅ fastjson2(过渡),尽快转 Jackson/Gson |