Jackson使用詳解

JSON

Jackson是java提供處理json數據序列化和反序列的工具類,在使用Jackson處理json前,我們得先掌握json。

JSON數據類型

類型示例說明
字符串(String)"hello"雙引號包裹,支持轉義字符(如?\n)。
數字(Number)42,?3.14,?-1e5整數、浮點數或科學計數法表示。
布爾值(Boolean)true,?false僅兩個值,表示邏輯真/假。
對象(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
繁體地址,請注明出處:http://hk.pswp.cn/news/906022.shtml
英文地址,請注明出處:http://en.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…