亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何解決JSON反序列化Long變Integer或Double的問題

發布時間:2022-03-04 10:59:33 來源:億速云 閱讀:284 作者:小新 欄目:開發技術

這篇文章主要為大家展示了“如何解決JSON反序列化Long變Integer或Double的問題”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領大家一起研究并學習一下“如何解決JSON反序列化Long變Integer或Double的問題”這篇文章吧。

一、背景

工作中可能會遇到對 Map<String,Object> 進行 JSON 序列化,其中值中包含 Long 類型的數據,反序列化后強轉 Long 時報類型轉換異常的問題。

本文簡單探討下該問題,并給出解決方案,如果你想直接看建議,直接翻到第三部分即可。

二、研究

本文主要以 jackson、 gson、fastjson 三個庫為例,版本分別如下:

   <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.13.0</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.13.0</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.78</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.8</version>
        </dependency>

代碼示例

package json;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.GsonBuilder;
import java.util.HashMap;
import java.util.Map;
public class ObjectDemo {
    public static void main(String[] args) throws JsonProcessingException {
        Map<String, Object> dataMap = new HashMap<>(2);
        dataMap.put("aInteger", 1);
        dataMap.put("aLong", 2L);
        String jsonStr = JSON.toJSONString(dataMap);
        System.out.println(jsonStr);
        // fastjson
        System.out.println("--- fastjson -----");
        Map<String, Object> fastMap = JSON.parseObject(jsonStr, new com.alibaba.fastjson.TypeReference<Map<String, Object>>() {
        });
        printMap(fastMap);
        System.out.println("--- gson -----");
        Map<String, Object> gsonMap = new GsonBuilder().create()
                .fromJson(jsonStr, (new TypeReference<Map<String, Object>>(){}).getType() );
        printMap(gsonMap);
        System.out.println("--- jackson -----");
        ObjectMapper objectMapper = new ObjectMapper();
        Map<String, Object> jacksonMap = objectMapper.readValue(jsonStr, new TypeReference<Map<String, Object>>() {
        });
        printMap(jacksonMap);
    }
    private static void printMap(Map<String, Object> map) {
        map.forEach((key, value) -> {
            System.out.println("key:" + key + ",value=" + value + ",valueClass=" + value.getClass());
        });
    }
}

運行結果:

{"aInteger":1,"aLong":2}
--- fastjson -----
key:aLong,value=2,valueClass=class java.lang.Integer
key:aInteger,value=1,valueClass=class java.lang.Integer
--- gson -----
key:aInteger,value=1.0,valueClass=class java.lang.Double
key:aLong,value=2.0,valueClass=class java.lang.Double
--- jackson -----
key:aInteger,value=1,valueClass=class java.lang.Integer
key:aLong,value=2,valueClass=class java.lang.Integer

aLong 雖然原始類型為 Long 但是 fastjson 和 jackson 中被反序列化為 Integer 類型,gson 中被映射為 Double 類型。

我們觀察序列化后的 json 字符串:

{"aInteger":1,"aLong":2}

會發現其實 JSON 中并沒有包含類型信息,而反序列化的類型為 Map.class 或者 Map<String,Object> 類型,當你只知道這些信息時,你無法得知 aLong 原始類型為 Long 。

因此不同的JSON 序列化工具給出了自己的默認處理行為。

當我們把 aLong 的值調整到 超過 (Integer.MAX_VALUE,Long.MAX_VALUE] 的范圍之間時,fastjson 和 jackson 可以解析為 Long 類型。

 Map<String, Object> dataMap = new HashMap<>(2);
        dataMap.put("aInteger", 1);
        dataMap.put("aLong", Long.MAX_VALUE);

輸出的結果:

{"aInteger":1,"aLong":9223372036854775807}
--- fastjson -----
key:aLong,value=9223372036854775807,valueClass=class java.lang.Long
key:aInteger,value=1,valueClass=class java.lang.Integer
--- gson -----
key:aInteger,value=1.0,valueClass=class java.lang.Double
key:aLong,value=9.223372036854776E18,valueClass=class java.lang.Double
--- jackson -----
key:aInteger,value=1,valueClass=class java.lang.Integer
key:aLong,value=9223372036854775807,valueClass=class java.lang.Long

我們大致了解到, fastjson 和 jackson 默認情況下整數類型優先選取 Integer ,超過 Integer 范圍再選擇 Long ,以此類推。

而當我們放入 Float 類型時,結果又有差異:

   Map<String, Object> dataMap = new HashMap<>(2);
        dataMap.put("aInteger", 1);
        dataMap.put("aFLoat", 0.1F);

運行結果:

{"aInteger":1,"aFLoat":0.1}
--- fastjson -----
key:aInteger,value=1,valueClass=class java.lang.Integer
key:aFLoat,value=0.1,valueClass=class java.math.BigDecimal
--- gson -----
key:aInteger,value=1.0,valueClass=class java.lang.Double
key:aFLoat,value=0.1,valueClass=class java.lang.Double
--- jackson -----
key:aInteger,value=1,valueClass=class java.lang.Integer
key:aFLoat,value=0.1,valueClass=class java.lang.Double

fastjson 中 Float 被解析為 BigDecimal, gson 和 jackson 中被解析為 Double 類型。

具體底層如何處理,大家可以對每個框架的反序列方法單步跟進去即可得到答案。

這里以 fastjson 為例,簡單調試下:

fastjson 底通過 com.alibaba.fastjson.parser.ParserConfig#getDeserializer 方法獲取當前類型的反序列化器為 MapDeserializer

執行其反序列化方法:

com.alibaba.fastjson.parser.deserializer.MapDeserializer#deserialze

如何解決JSON反序列化Long變Integer或Double的問題

通過 com.alibaba.fastjson.parser.deserializer.MapDeserializer#parseMap 對 Map 類型進行解析。

如何解決JSON反序列化Long變Integer或Double的問題

由于 Map<String, Object>的 valueType 類型為 Object,因此對 aFloat 使用 JavaObjectDeserializer 反序列化器進行解析。

如何解決JSON反序列化Long變Integer或Double的問題

跟進 lexer.decimalValue 看下:

如何解決JSON反序列化Long變Integer或Double的問題

最終通過 com.alibaba.fastjson.parser.JSONScanner#decimalValue 將 aFloat 解析為 BigDecimal 類型。

三、如何解決

3.0 將類型寫入 JSON 字符串中

如果我們能將原始類型寫入到 JSON 字符串中,那么反序列化時自然就可以復原原始的類型。

在 fastjson 中可以使用 SerializerFeature.WriteClassName

package json;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import java.util.HashMap;
import java.util.Map;
public class JsonDemo {
    public static void main(String[] args) {
        Map<String, Object> dataMap = new HashMap<>(2);
        dataMap.put("aInteger", 1);
        dataMap.put("aLong", 2L);
        dataMap.put("aFloat", 3F);
        String jsonStr = JSON.toJSONString(dataMap, SerializerFeature.WriteClassName);
        System.out.println(jsonStr);
        // fastjson
        System.out.println("--- fastjson -----");
        Map<String, Object> fastMap = JSON.parseObject(jsonStr, new com.alibaba.fastjson.TypeReference<Map<String, Object>>() {
        });
        printMap(fastMap);
    }
    private static void printMap(Map<String, Object> map) {
        map.forEach((key, value) -> {
            System.out.println("key:" + key + ",value=" + value + ",valueClass=" + value.getClass());
        });
    }
}

打印的結果

{"@type":"java.util.HashMap","aFloat":3.0F,"aInteger":1,"aLong":2L}
--- fastjson -----
key:aLong,value=2,valueClass=class java.lang.Long
key:aFloat,value=3.0,valueClass=class java.lang.Float
key:aInteger,value=1,valueClass=class java.lang.Integer

雖然,這種方法可以解決問題,但是這也通常要求序列化和反序列化使用同一個 JSON 工具

比如上面的 {"@type":"java.util.HashMap","aFloat":3.0F,"aInteger":1,"aLong":2L} 直接使用 jackson 進行反序列化會報錯:

 System.out.println("--- jackson -----");
        ObjectMapper objectMapper = new ObjectMapper();
        Map<String, Object> jacksonMap = objectMapper.readValue(jsonStr, new TypeReference<Map<String, Object>>() {
        });
        printMap(jacksonMap);

報錯內容:

--- jackson -----
Exception in thread "main" com.fasterxml.jackson.core.JsonParseException: Unexpected character ('F' (code 70)): was expecting comma to separate Object entries
 at [Source: (String)"{"@type":"java.util.HashMap","aFloat":3.0F,"aInteger":1,"aLong":2L}"; line: 1, column: 43]
    at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:2391)
    at com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.java:735)
    at com.fasterxml.jackson.core.base.ParserMinimalBase._reportUnexpectedChar(ParserMinimalBase.java:659)

3.1 提供 POJO 類,慎對 Map<String,Object> 序列化

強烈建議不要怕麻煩,直接定義 POJO 類。

不僅不受 JSON 框架的約束,而且對方解析時也非常明確,不容易出錯。

如工作中在發送MQ 消息時很多人圖方便,不想定義POJO 對象,因為這樣通常需要打包比較麻煩,就將要傳輸給其他系統的數據定義為 Map 類型,下游再根據 key 去解析,這是一個非常不好的習慣。

很容易造成上下游類型不一致,造成更換 JSON 反序列化工具時出現故障。

因此發送 MQ 消息時,最好給出相應的 POJO 類。

實際工作中,還遇到有同學將 Map<String,Object> 使用 JSON 序列化的方式存儲到 Redis 中,然后反序列化后,將原本 Long 類型的值,強轉為 Long 導致線上出現BUG(前面講到,這種情況下使用 fastjson 時,如果值小于整數最大值,反序列化為 Integer 類型,強轉必然會報錯)。

3.2 反序列化自定義類

如果上游序列化是 Map<String,Object>, 如果類型核實清楚,我們依然可以自定義 POJO 類來反序列化。

@lombok.Data
public class Data {
    private Float aFloat;
    private Integer aInteger;
}
  Map<String, Object> dataMap = new HashMap<>(2);
        dataMap.put("aInteger", 1);
        dataMap.put("aFLoat", 0.1F);
        String jsonStr = JSON.toJSONString(dataMap);
        Data data = JSON.parseObject(jsonStr, Data.class);
        System.out.println(data);

輸出結果:

Data(aFloat=0.1, aInteger=1)

可能有些同學會覺得定義 POJO 類很麻煩,其實我們可以使用 IDEA 插件或者在線工具實現 JSON 字符串生成 POJO 類。

如 Json2Pojo IDEA 插件

和一些在線生成工具:

https://json2csharp.com/json-to-pojo

如何解決JSON反序列化Long變Integer或Double的問題

https://www.javainuse.com/pojo

如何解決JSON反序列化Long變Integer或Double的問題

以上是“如何解決JSON反序列化Long變Integer或Double的問題”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

萍乡市| 东丽区| 霍林郭勒市| 营山县| 肥东县| 桐乡市| 浦江县| 石家庄市| 海南省| 栾城县| 西乌珠穆沁旗| 宜黄县| 建德市| 读书| 禄丰县| 桂林市| 大同市| 兴宁市| 邵东县| 封开县| 广河县| 故城县| 武川县| 黎川县| 岑溪市| 金溪县| 罗源县| 揭阳市| 平江县| 胶州市| 渭南市| 华坪县| 丹凤县| 平塘县| 德安县| 泉州市| 陵川县| 金堂县| 瑞金市| 吕梁市| 衡山县|