Java常用的JSON

在 Java 中把对象转换为 JSON 对象(或 JSON 字符串),核心依赖 JSON 解析库,主流有 Jackson (Spring 内置)、FastJSON (阿里)、Gson(Google),以下是三种库的完整实现方案,包含核心 API、示例代码和避坑指南:

一、先明确:"JSON 对象" 的两种形态

  1. JSON 字符串 :最常用(如 {"name":"张三","age":20}),用于网络传输、存储;
  2. JSON 对象(树形结构) :如 Jackson 的 JsonNode、FastJSON 的 JSONObject,用于动态操作 JSON 节点(如新增 / 删除字段)。

二、方案 1:Jackson(Spring Boot 内置,推荐)

Spring Boot 项目默认集成 Jackson,无需额外引入核心依赖(非 Spring 项目需手动引入)。

1. 依赖引入(非 Spring 项目)
复制代码
<!-- Jackson 核心依赖 -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.15.2</version>
</dependency>
<!-- 可选:支持 JDK8+ 时间类型(LocalDateTime) -->
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>2.15.2</version>
</dependency>
2. 核心用法
(1)对象转 JSON 字符串
复制代码
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Date;

// 测试实体类
class User {
    private String name;
    private Integer age;
    private Date createTime; // 时间字段
    // 必须有无参构造器(Jackson 反射实例化需要)
    public User() {}
    // getter/setter 必须有(Jackson 通过 getter 读取字段)
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public Integer getAge() { return age; }
    public void setAge(Integer age) { this.age = age; }
    public Date getCreateTime() { return createTime; }
    public void setCreateTime(Date createTime) { this.createTime = createTime; }
}

public class JacksonDemo {
    // 全局 ObjectMapper(线程安全,建议单例)
    private static final ObjectMapper objectMapper = new ObjectMapper();

    public static void main(String[] args) throws Exception {
        // 1. 构建对象
        User user = new User();
        user.setName("张三");
        user.setAge(20);
        user.setCreateTime(new Date());

        // 2. 对象转 JSON 字符串
        String jsonStr = objectMapper.writeValueAsString(user);
        System.out.println("JSON 字符串:" + jsonStr);
        // 输出示例:{"name":"张三","age":20,"createTime":1717238400000}
    }
}
(2)对象转 JSON 树形对象(JsonNode)

用于动态操作 JSON 节点(如修改字段、判断字段是否存在):

复制代码
public static void main(String[] args) throws Exception {
    User user = new User();
    user.setName("张三");
    user.setAge(20);

    // 1. 对象转 JsonNode(JSON 树形对象)
    com.fasterxml.jackson.databind.JsonNode jsonNode = objectMapper.valueToTree(user);

    // 2. 操作 JsonNode
    String name = jsonNode.get("name").asText(); // 获取字段值
    int age = jsonNode.get("age").asInt();       // 转换为int
    boolean hasCreateTime = jsonNode.has("createTime"); // 判断字段是否存在

    System.out.println("name:" + name + ",age:" + age + ",有createTime?" + hasCreateTime);
    // 输出:name:张三,age:20,有createTime?false
}
(3)自定义序列化规则(如日期格式)
复制代码
// 配置 ObjectMapper 自定义规则
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); // 日期格式
objectMapper.configure(com.fasterxml.jackson.databind.SerializationFeature.FAIL_ON_EMPTY_BEANS, false); // 忽略空对象报错
objectMapper.setSerializationInclusion(com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL); // 忽略null字段

// 转换后 JSON 示例:{"name":"张三","age":20,"createTime":"2025-06-01 10:00:00"}

三、方案 2:FastJSON(阿里,轻量高效)

FastJSON 是阿里开源的高性能 JSON 库,适合追求解析速度的场景。

1. 依赖引入
复制代码
<!-- FastJSON 2.x 版本(推荐,性能更优) -->
<dependency>
    <groupId>com.alibaba.fastjson2</groupId>
    <artifactId>fastjson2</artifactId>
    <version>2.0.32</version>
</dependency>
<!-- 兼容 1.x 版本(如需) -->
<!--
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.83</version>
</dependency>
-->
2. 核心用法
(1)对象转 JSON 字符串
复制代码
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONWriter;
import java.util.Date;

public class FastJsonDemo {
    public static void main(String[] args) {
        User user = new User();
        user.setName("李四");
        user.setAge(25);
        user.setCreateTime(new Date());

        // 1. 基础转换
        String jsonStr = JSON.toJSONString(user);
        System.out.println("基础JSON:" + jsonStr);

        // 2. 自定义规则(忽略null、格式化日期、美化输出)
        String jsonStrCustom = JSON.toJSONString(
            user,
            JSONWriter.Feature.WriteNulls, // 显示null字段(默认忽略)
            JSONWriter.Feature.PrettyFormat, // 美化输出(换行缩进)
            JSONWriter.Feature.WriteDateUseDateFormat // 日期格式化(默认yyyy-MM-dd HH:mm:ss)
        );
        System.out.println("自定义JSON:" + jsonStrCustom);
    }
}
(2)对象转 JSON 对象(JSONObject)
复制代码
public static void main(String[] args) {
    User user = new User();
    user.setName("李四");
    user.setAge(25);

    // 1. 对象转 JSONObject(FastJSON 树形对象)
    com.alibaba.fastjson2.JSONObject jsonObject = (com.alibaba.fastjson2.JSONObject) JSON.toJSON(user);

    // 2. 操作 JSONObject
    String name = jsonObject.getString("name");
    int age = jsonObject.getIntValue("age");
    jsonObject.put("gender", "男"); // 新增字段

    System.out.println("JSON对象:" + jsonObject);
    // 输出:{"age":25,"gender":"男","name":"李四"}
}

四、方案 3:Gson(Google,简洁易用)

Gson 是 Google 开源的 JSON 库,API 设计简洁,适合跨平台场景。

1. 依赖引入
复制代码
<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.10.1</version>
</dependency>
2. 核心用法
(1)对象转 JSON 字符串
复制代码
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.util.Date;

public class GsonDemo {
    // 全局 Gson(线程安全)
    private static final Gson gson = new GsonBuilder()
            .setDateFormat("yyyy-MM-dd HH:mm:ss") // 日期格式
            .serializeNulls() // 显示null字段
            .setPrettyPrinting() // 美化输出
            .create();

    public static void main(String[] args) {
        User user = new User();
        user.setName("王五");
        user.setAge(30);
        user.setCreateTime(new Date());

        // 对象转 JSON 字符串
        String jsonStr = gson.toJson(user);
        System.out.println("Gson JSON:" + jsonStr);
    }
}
(2)对象转 JSON 树形对象(JsonObject)
复制代码
public static void main(String[] args) {
    User user = new User();
    user.setName("王五");
    user.setAge(30);

    // 1. 对象转 JsonElement(父类),强转为 JsonObject
    com.google.gson.JsonObject jsonObject = gson.toJsonTree(user).getAsJsonObject();

    // 2. 操作 JsonObject
    String name = jsonObject.get("name").getAsString();
    int age = jsonObject.get("age").getAsInt();
    jsonObject.addProperty("gender", "女"); // 新增字段

    System.out.println("Gson JSON对象:" + jsonObject);
    // 输出:{"name":"王五","age":30,"gender":"女"}
}

五、核心注意事项(避坑指南)

1. 基础要求(所有库通用)
  • 实体类必须有 无参构造器(Jackson/Gson 反射实例化需要,FastJSON 可兼容,但建议统一);
  • 字段必须有 getter 方法(序列化时读取字段值,FastJSON 可直接读字段,但 getter 更规范);
  • 避免循环引用(如 A 包含 B,B 包含 A),否则会报栈溢出错误:
    • Jackson:objectMapper.configure(SerializationFeature.FAIL_ON_CIRCULAR_REFERENCES, false)
    • FastJSON:JSON.toJSONString(user, SerializerFeature.DisableCircularReferenceDetect)
    • Gson:默认忽略循环引用(无需额外配置)。
2. 日期类型处理
  • 直接转换会得到时间戳(如 1717238400000),需手动配置日期格式(如 yyyy-MM-dd HH:mm:ss);
  • JDK8+ 时间类型(LocalDateTime/LocalDate):Jackson 需引入 jackson-datatype-jsr310,FastJSON/Gson 天然支持。
3. null 字段处理
  • Jackson:objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL)
  • FastJSON:默认忽略 null,需 JSONWriter.Feature.WriteNulls 显示;
  • Gson:默认忽略 null,需 GsonBuilder.serializeNulls() 显示。

六、库的选型建议

优点 缺点 适用场景
Jackson Spring 内置、稳定、功能全面 性能略低于 FastJSON Spring 项目、企业级开发
FastJSON 性能最高、轻量、API 简洁 早期版本有安全漏洞(需用 2.x) 高性能场景、阿里生态项目
Gson Google 维护、跨平台、易上手 性能一般 跨平台项目、小型应用

七、总结

  1. 快速转换为 JSON 字符串
    • Jackson:new ObjectMapper().writeValueAsString(obj)
    • FastJSON:JSON.toJSONString(obj)
    • Gson:new Gson().toJson(obj)
  2. 转换为 JSON 树形对象 (动态操作):
    • Jackson:objectMapper.valueToTree(obj)(JsonNode);
    • FastJSON:(JSONObject) JSON.toJSON(obj)
    • Gson:gson.toJsonTree(obj).getAsJsonObject()
  3. 核心原则:Spring 项目优先用 Jackson(无需额外依赖),追求性能用 FastJSON 2.x,简单场景用 Gson。
相关推荐
火山灿火山3 小时前
Qt常用控件(三)
开发语言·qt
利刃大大4 小时前
【JavaSE】十三、枚举类Enum && Lambda表达式 && 列表排序常见写法
java·开发语言·枚举·lambda·排序
float_六七4 小时前
Java反射:万能遥控器拆解编程
java·开发语言
han_hanker4 小时前
java 异常类——详解
java·开发语言
源码获取_wx:Fegn08954 小时前
基于springboot + vue健身房管理系统
java·开发语言·前端·vue.js·spring boot·后端·spring
LinHenrY12274 小时前
初识C语言(自定义结构:结构体)
c语言·开发语言
峥嵘life4 小时前
Android16 EDLA 认证测试CTS问题分析解决
android·java·服务器
Matlab仿真实验室4 小时前
基于Matlab实现可见光通信仿真
开发语言·matlab
Mr1ght4 小时前
为什么 InheritableThreadLocal 在 Spring 线程池中“偶尔”能传递变量?——一次线程池上下文传播的误解
java·spring