Jackson使用详解

JSON

Jackson是java提供处理json数据序列化和反序列的工具类,在使用Jackson处理json前,我们得先掌握json。

JSON数据类型

类型示例说明
字符串(String)"hello"双引号包裹,支持转义字符(如 \n)。
数字(Number)423.14-1e5整数、浮点数或科学计数法表示。
布尔值(Boolean)truefalse仅两个值,表示逻辑真/假。
对象(Object){ "key": "value" }无序的键值对集合。
数组(Array)[1, 2, 3]有序的值列表。
Nullnull表示空值或占位符。

例如:

# 类型: Map<String,List<T>>
{"B": [{"id": "1666364264118235829","sort": 1,"originalPrice": "20.00"},{"id": "1666364264118235829","sort": 2,"originalPrice": "10.00"},{"id": "1666364264118235829","sort": 3,"originalPrice": "15.00"}]
}
# 类型:Map<String,T>
{"A": {"userWithdrawDayCountLimit": 2,"userWithdrawDayAmountLimit": "100.00","userWithdrawTotalAmountLimit": "100.00","userPacketDayCountLimit": 100,"platformWithdrawDayAmountLimit": "1000.00"},"B": {"userWithdrawDayCountLimit": 3,"userWithdrawDayAmountLimit": "100.00","userWithdrawTotalAmountLimit": "100.00","userPacketDayCountLimit": 100,"platformWithdrawDayAmountLimit": "1000.00"},"D1": {"userWithdrawDayCountLimit": 2,"userWithdrawDayAmountLimit": "100.00","userWithdrawTotalAmountLimit": "100.00","userPacketDayCountLimit": 100,"platformWithdrawDayAmountLimit": "1000.00"}
}
#类型:T
{"open": false,"reachIndex": false,"reachRemain": false,"withdrawReachRemain": false,"pushAcJoin": false,"pushWithdraw": false
}
#类型:Map<String,T>
# T 包含 List<Map<BigDecimal, Double>> Map<BigDecimal, Double> Map<BigDecimal, Double> Integer
{"A": {"fixed": [{"10.00": 1.00}, {"1.88": 1.00}, {"1.66": 1.00}, {"0.88": 1.00}, {"0.66": 1.00}],"general": {"0.01": 0.40,"0.02": 0.25,"0.03": 0.20,"0.04": 0.10,"0.05": 0.05},"big": {"0.06": 0.10,"0.08": 0.30,"0.10": 0.40,"0.15": 0.20},"generalToBig": 9},"B": {"fixed": [{"10.00": 1.00}, {"1.88": 1.00}, {"1.66": 1.00}, {"0.88": 1.00}, {"0.66": 1.00}],"general": {"0.01": 0.40,"0.02": 0.25,"0.03": 0.20,"0.04": 0.10,"0.05": 0.05},"big": {"0.06": 0.10,"0.08": 0.30,"0.10": 0.40,"0.15": 0.20},"generalToBig": 9}
}

 JSON易错点

大整数精度丢失

  • 问题:JavaScript等语言使用双精度浮点数(64位)表示所有数字,超过 2^53 的整数无法精确表示。

  • 示例

    #JSON.parse 后会变成 9007199254740992(精度丢失){ "id": 9007199254740993 }
  • 解决方案:将大整数以字符串传输,特别是开发场景中数据库主键ID采用雪花算法生成ID,很长,得用字符串

浮点数精度问题

  • 问题:浮点数在不同系统间传输时可能因精度差异导致微小误差。

  • 示例

{ "price": 0.1 }
  • 二进制浮点数0.1 无法精确表示,可能导致累加误差(如 0.1 + 0.2 ≠ 0.3),推荐使用BigDecimal类型。

Jackson

切入正题,在 Java 中使用 Jackson 库处理 JSON 时,数字类型的序列化(对象转JSON)和反序列化(JSON转对象)需要特别注意数据类型映射、精度问题和配置选项。

Jackson的使用

//反序列化 
String outputJson = mapper.writeValueAsString(order);
//序列化
Order order = mapper.readValue(json, Order.class);

Jackson注解

注解场景用途
@JsonProperty映射 JSON 字段名 order_id 到 Java 字段 id
@JsonFormat将 id 序列化为字符串,createTime 格式化为指定日期格式。
@JsonCreator定义工厂方法,用于反序列化时构造 Order 对象。
@JsonValue序列化 OrderStatus 枚举时输出中文描述(而非枚举名称)。
@JsonDeserialize自定义 discountCode 字段的反序列化逻辑(从字符串提取数字)。
@JsonIgnore序列化和反序列化忽略该字段

用一个场景玩转这些注解~

假设订单对象 Order 包含以下需求:

  1. 订单号(id):后端字段为 Long,但前端要求传输为字符串(避免大整数精度丢失)。

  2. 下单时间(createTime):以 yyyy-MM-dd HH:mm:ss 格式传输。

  3. 订单状态(status):枚举类型,序列化时输出中文描述,反序列化时支持数字和字符串。

  4. 自定义折扣码(discountCode):需要将字符串格式 "DISCOUNT-1001" 转换为纯数字 1001 存储。

  5. 订单创建方式:通过工厂方法反序列化 JSON。

完整代码实现

1. 订单状态枚举(使用 @JsonValue 和 @JsonCreator

public enum OrderStatus {UNPAID(0, "未支付"),PAID(1, "已支付"),CANCELLED(2, "已取消");private final int code;private final String desc;OrderStatus(int code, String desc) {this.code = code;this.desc = desc;}// 序列化时输出中文描述@JsonValuepublic String getDesc() {return desc;}// 反序列化时支持从数字或字符串解析@JsonCreatorpublic static OrderStatus from(Object value) {if (value instanceof Integer) {int code = (Integer) value;for (OrderStatus status : values()) {if (status.code == code) return status;}} else if (value instanceof String) {String desc = (String) value;for (OrderStatus status : values()) {if (status.desc.equals(desc)) return status;}}throw new IllegalArgumentException("无效的订单状态值: " + value);}
}

 2. 自定义折扣码反序列化器(使用 @JsonDeserialize

// 自定义反序列化逻辑:将 "DISCOUNT-1001" 转换为 1001
public class DiscountCodeDeserializer extends JsonDeserializer<Integer> {@Overridepublic Integer deserialize(JsonParser p, DeserializationContext ctx) throws IOException {String text = p.getText();return Integer.parseInt(text.replace("DISCOUNT-", ""));}
}

3. 订单对象(使用 @JsonFormat@JsonProperty 和 @JsonCreator

public class Order {@JsonProperty("order_id") // JSON 字段名为 order_id,映射到 id 字段@JsonFormat(shape = JsonFormat.Shape.STRING) // 序列化为字符串private Long id;@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")private Date createTime;private OrderStatus status;@JsonDeserialize(using = DiscountCodeDeserializer.class) // 指定自定义反序列化器private Integer discountCode;// 使用工厂方法反序列化(@JsonCreator)@JsonCreatorpublic static Order create(@JsonProperty("order_id") Long id,@JsonProperty("createTime") Date createTime,@JsonProperty("status") OrderStatus status,@JsonProperty("discountCode") Integer discountCode) {Order order = new Order();order.id = id;order.createTime = createTime;order.status = status;order.discountCode = discountCode;return order;}// Getter/Setter 省略
}

 4. 测试序列化与反序列化

public class OrderExample {public static void main(String[] args) throws JsonProcessingException {ObjectMapper mapper = new ObjectMapper();mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));// 反序列化测试String json = "{"+ "\"order_id\": \"1234567890123456789\","+ "\"createTime\": \"2023-10-01 14:30:00\","+ "\"status\": 1," // 使用数字反序列化+ "\"discountCode\": \"DISCOUNT-1001\""+ "}";Order order = mapper.readValue(json, Order.class);System.out.println("反序列化结果: " + order.getStatus().getDesc()); // 输出: 已支付System.out.println("折扣码: " + order.getDiscountCode()); // 输出: 1001// 序列化测试order.setStatus(OrderStatus.CANCELLED);String outputJson = mapper.writeValueAsString(order);System.out.println("序列化结果: " + outputJson);// 输出: {"order_id":"1234567890123456789","createTime":"2023-10-01 14:30:00","status":"已取消","discountCode":1001}}
}

Jackson的常见问题

Jackson 根据目标字段的类型自动推断数字类型,若类型不匹配可能抛出异常。例如:

public class Example {private int value; // 目标字段类型
}// JSON: {"value": 10000000000} (超过 int 范围)
// 反序列化时会抛出 `JsonMappingException: Numeric value (10000000000) out of range of int`

 Java 的 Long 类型最大值为 9,223,372,036,854,775,807,超过此值需用 BigInteger,例如:

public class BigNumberExample {private BigInteger id; // 使用 BigInteger 接收大整数
}// JSON: {"id": 123456789012345678901234567890}
//若目标字段为 Long 但值过大,会抛出 MismatchedInputException

double 或 float 类型可能导致精度丢失,使用 BigDecimal 替代

public class PrecisionExample {@JsonFormat(shape = JsonFormat.Shape.STRING) // 以字符串形式传输private BigDecimal price;
}// JSON: {"price": "0.1"} (字符串形式避免二进制精度问题)
异常类型原因解决方案
MismatchedInputExceptionJSON 数字无法转换为目标类型(如溢出)使用更大的数据类型(如 Long → BigInteger
InvalidFormatException数字格式错误(如非数字字符)校验输入数据或自定义反序列化逻辑
JsonParseExceptionJSON 语法错误(如 1,23 代替 1.23修复 JSON 格式

TypeReference类

使用 TypeReference 解决泛型类型擦除问题:

String json = "[{\"name\":\"Alice\"}, {\"name\":\"Bob\"}]";
List<User> users = mapper.readValue(json, new TypeReference<List<User>>() {});

假设需要将 JSON 数组 [{"name":"Alice"}, {"name":"Bob"}] 反序列化为 List<User>

String json = "[{\"name\":\"Alice\"}, {\"name\":\"Bob\"}]";
List<User> users = mapper.readValue(json, List.class); // 问题出现!

问题:由于泛型擦除,List.class 丢失了 User 的类型信息,Jackson 无法知道 List 中元素的类型,默认会反序列化为 List<LinkedHashMap>,而非 List<User>

解决方案:

List<User> users = mapper.readValue(json, new TypeReference<List<User>>() {} // 匿名内部类
);

例子:

错误用法(未处理泛型擦除)

String json = "[{\"name\":\"Alice\"}]";
List<User> users = mapper.readValue(json, List.class); // 返回 List<LinkedHashMap>
User user = users.get(0); // 抛出 ClassCastException: LinkedHashMap 无法转为 User

正确用法(使用 TypeReference)

String json = "[{\"name\":\"Alice\"}]";
List<User> users = mapper.readValue(json, new TypeReference<List<User>>() {}); // 正确返回 List<User>
User user = users.get(0); // 正常访问

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/news/906022.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言| 指针变量的定义

C语言| 指针的优点-CSDN博客 * 表示“指向”&#xff0c;为了说明指针变量和它所指向的变量之间的联系。 int * i&#xff1b;//表示指针变量i里面存放的地址&#xff0c;所指向的存储单元里的【数据】。 【指针变量的定义】 C语言规定所有变量&#xff0c;在使用前必须先定…

Java 快速转 C# 教程

以下是一个针对 Java 开发者快速转向 C# 的简明教程&#xff0c;重点对比 Java 与 C# 的异同&#xff0c;帮助你快速上手。 项目结构&#xff1a; .sln &#xff1a;解决方案文件&#xff0c;管理多个项目之间的依赖关系。.csproj &#xff1a;项目文件&#xff0c;定义目标框…

EasyExcel详解

文章目录 一、easyExcel1.什么是easyExcel2.easyExcel示例demo3.easyExcel read的底层逻辑~~4.easyExcel write的底层逻辑~~ 二、FastExcel1.为什么更换为fastExcel2.fastExcel新功能 一、easyExcel 1.什么是easyExcel 内容摘自官方&#xff1a;Java解析、生成Excel比较有名的…

jvm安全点(三)openjdk17 c++源码垃圾回收之安全点结束,唤醒线程

1. VMThread::inner_execute() - 触发安全点​​ cpp 复制 void VMThread::inner_execute(VM_Operation* op) { if (op->evaluate_at_safepoint()) { SafepointSynchronize::begin(); // 进入安全点&#xff0c;阻塞所有线程 // ...执行GC等操作... SafepointSynchronize::…

102. 二叉树的层序遍历递归法:深度优先搜索的巧妙应用

二叉树的层序遍历是一种经典的遍历方式&#xff0c;它要求按层级逐层访问二叉树的节点。通常我们会使用队列来实现层序遍历&#xff0c;但递归法也是一种可行且有趣的思路。本文将深入探讨递归法解决二叉树层序遍历的核心难点&#xff0c;并结合代码和模拟过程进行详细讲解。 …

首个窗口级无人机配送VLN系统!中科院LogisticsVLN:基于MLLM实现精准投递

导读 随着智能物流需求日益增长&#xff0c;特别是“最后一公里”配送场景的精细化&#xff0c;传统地面机器人逐渐暴露出适应性差、精度不足等瓶颈。为此&#xff0c;本文提出了LogisticsVLN系统——一个基于多模态大语言模型的无人机视觉语言导航框架&#xff0c;专为窗户级别…

WPF Datagrid 数据加载和性能

这篇文章并非讨论 WPF Datagrid 的性能数据&#xff0c;而只是简单介绍一下为了使其性能良好&#xff0c;你需要注意哪些方面。我不太想使用性能分析器来展示实际数据&#xff0c;而是尽可能地使用了 Stopwatch 类。这篇文章不会深入探讨处理海量数据的技术&#xff0c;例如分页…

matlab求矩阵的逆、行列式、秩、转置

inv - 计算矩阵的逆 用途&#xff1a;计算一个可逆矩阵的逆矩阵。 D [1, 2; 3, 4]; % 定义一个2x2矩阵 D_inv inv(D); % 计算矩阵D的逆 disp(D_inv);det - 计算矩阵的行列式 用途&#xff1a;计算方阵的行列式。 E [1, 2; 3, 4]; determinant det(E); % 计算行列式 disp…

ridecore流水线解读

文章目录 流水线stage分属前后端PCpipelineIFIDDPDP 与 SW 中间没有latchSWCOM 源码地址 流水线stage分属前后端 IF -> ID -> DP -> SW -> EX -> COM分类阶段说明前端IF指令获取阶段。PC 使用分支预测器&#xff0c;访问指令存储器。典型前端操作。前端ID解码并…

【SpringBoot】关于MP使用中配置了数据库表前缀的问题

problem 使用MP时&#xff0c;在application.yml配置文件中配置了MP匹配数据库表中的表名时的前缀作了规定&#xff0c;如下&#xff1a; 那么当我运行时报错了错误&#xff0c;报错信息如下&#xff1a; 因为我数据库表的书类表名是book&#xff0c;MP在匹配时使用了表名前…

印度Rummy游戏支付通道申请策略:技巧类游戏的合规与创新

本文为印度支付申请科普文&#xff0c;自去年开始&#xff0c;印度Rummy类游戏申请印度支付都需要拥有AIGF的会员及产品证书。 如需要rummy可以通过AIGF审核的源。码&#xff0c;或咨询AIGF的相关内容&#xff0c;可以联。系老妙。 印度作为全球棋牌类游戏增长最快的市场之一&…

日志与策略模式

什么是设计模式 IT⾏业 ,为了让 菜鸡们不太拖⼤佬的后腿, 于是⼤佬们针对⼀些经典的常⻅的场景, 给定了⼀些对应的解决⽅案, 这个就是 设计模式 日志认识 计算机中的⽇志是记录系统和软件运⾏中发⽣事件的⽂件&#xff0c;主要作⽤是监控运⾏状态、记录异常信 息&#xff…

解锁Ubuntu高效部署!自动安装配置文件YAML全解析

我们之前介绍了两种Ubuntu系统的安装方式&#xff0c;分别对应桌面版&#xff08;准备搞OpenStack了&#xff0c;先装一台最新的Ubuntu 23.10&#xff09;和服务器版&#xff08;Ubuntu 22.04 LTS服务器版本安装演示&#xff09;。但对于有些用户&#xff0c;因为技术问题&…

关系代数和关系数据库语言(SQL)

阅读提示&#xff1a;本篇文章较长&#xff0c;建议从目录上选取想看的内容。代码上的话&#xff0c;我习惯用小写&#xff0c;如果看不习惯建议跳过。有问题欢迎讨论&#xff01;&#xff01;&#xff01; 一、基础概念 1.1数据库的概念 数据库(Database)是按照数据结构来组…

EXO 可以将 Mac M4 和 Mac Air 连接起来,并通过 Ollama 运行 DeepSeek 模型

EXO 可以将 Mac M4 和 Mac Air 连接起来&#xff0c;并通过 Ollama 运行 DeepSeek 模型。以下是具体实现方法&#xff1a; 1. EXO 的分布式计算能力 EXO 是一个支持 分布式 AI 计算 的开源框架&#xff0c;能够将多台 Mac 设备&#xff08;如 M4 和 Mac Air&#xff09;组合成…

区块链基本理解

文章目录 前言一、什么是分布式账本(DLT)二、什么是P2P网络?二、共识算法三、密码算法前言 区块链是由一个一个数据块组成的链条,按照时间顺序将数据块逐一链接,通过哈希指针链接,所有的数据块共同维护一份分布式账本(DLT),每个节点(可以理解为一个玩家,一台计算机)都拥…

Node.js中的洋葱模型

文章目录 前言 前言 Node.js中的洋葱模型是一种中间件执行机制&#xff0c;主要用于处理HTTP请求和响应的流程控制。该模型通过层层包裹的中间件结构&#xff0c;实现请求从外到内穿透、响应从内向外返回的顺序执行。以下从核心概念、实现原理、框架差异及实际应用等方面解析&…

UI-TARS Desktop:用自然语言操控电脑,AI 重新定义人机交互

在人工智能技术飞速发展的今天,从文本生成到图像识别,AI 的能力边界不断被打破。而字节跳动近期开源的 UI-TARS Desktop,则将这一技术推向了更复杂的交互场景——通过自然语言直接控制计算机界面,实现了图形用户界面(GUI)的智能化自动化。这款工具不仅降低了操作门槛,更…

一个可拖拉实现列表排序的WPF开源控件

从零学习构建一个完整的系统 推荐一个可通过拖拉&#xff0c;来实现列表元素的排序的WPF控件。 项目简介 gong-wpf-dragdrop是一个开源的.NET项目&#xff0c;用于在WPF应用程序中实现拖放功能&#xff0c;可以让开发人员快速、简单的实现拖放的操作功能。 可以在同一控件内…

C语言中字符串函数的详细讲解

C语言提供了丰富的字符串处理函数&#xff0c;这些函数在<string.h>头文件中声明。以下是一些常用字符串函数的详细讲解&#xff1a; 字符串拷贝函数 strcpy 功能&#xff1a;将源字符串&#xff08;包括结尾的\0&#xff09;复制到目标字符串。原型&#xff1a;char *s…