替换 FastJSON:推荐 Jackson 及详细用法指南(含工具类 + 替换方案)

发布于:2025-05-14 ⋅ 阅读:(11) ⋅ 点赞:(0)

系列文章:
替换 FastJSON:推荐 Jackson 及详细用法指南(含工具类 + 替换方案)
总结下Jackson 中的JsonNode,ObjectNode,ArrayNode的方法
JsonNode 和 ObjectNode的区别以及他们能互换吗
Jackson 使用问题记录(持续更新)

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 包含了 coreannotations,一般只需引入此依赖即可。


三、Jackson 常用用法详解

1.Java 对象转 JSON 字符串

	//Java 对象转 JSON 字符串
   @Test
   public 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 对象
    @Test
    public 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 这个类,取而代之的是 JsonNodeObjectNode。理解这两个类的区别和使用方法,对于从 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 数组

	@Test
    public 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

@Test
    public 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.自定义日期格式

	@Test
    public 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)

	@Test
    public 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)

六、替换步骤建议

  1. 创建 JsonUtils 工具类(见上文)

  2. 全局搜索替换关键字

    • JSON.toJSONString(JsonUtils.toJson(
    • JSON.parseObject(JsonUtils.fromJson(
    • new TypeReference<new TypeReference<
    • JSON.parseArray(JsonUtils.toList(
  3. 测试验证:对关键模块进行单元测试或接口测试,确保序列化/反序列化结果一致。

  4. 逐步上线:先灰度发布部分功能,确认无误后再全面切换。


七、补充建议

建议 说明
✅ 统一 JSON 处理入口 使用 JsonUtils 类统一调用,方便后期替换底层库
✅ 避免手动拼接 JSON 易出错且难以维护,应始终使用序列化库生成 JSON
✅ 开启 Jackson 的严格模式 防止非法字段、未知字段导致错误
✅ 使用泛型支持复杂结构 TypeReference 支持嵌套结构、集合类型
✅ 日志中打印 JSON 时使用 pretty print 方便调试,可使用 mapper.writerWithDefaultPrettyPrinter()

八、不同项目选择json库总结

场景 推荐库
Spring Boot 项目 ✅ Jackson
微服务、分布式系统 ✅ Jackson
Android / Kotlin 项目 ✅ Moshi
简单工具类或小项目 ✅ Gson
已有项目迁出 FastJSON ✅ fastjson2(过渡),尽快转 Jackson/Gson

网站公告

今日签到

点亮在社区的每一天
去签到