Hessian序列化BigDecimal字段數(shù)據(jù)丟失

問題描述

訂單服務(wù)收到支付系統(tǒng)的消息,消息通過Hessian序列化刽漂,發(fā)現(xiàn)交易金額字段BigDecimal amount為0.00?出現(xiàn)這個問題大概分析一下芹枷,檢查消息發(fā)送日志,交易金額是不為零的莲趣,問題可能是Hessian序列化BigDecimal數(shù)據(jù)丟失鸳慈,臨時解決方案,把BigDecimal類型換成String喧伞。Hessian 4.0.33

深究原因

表面現(xiàn)象是Hessian序列化BigDecimal類型數(shù)據(jù)丟失蝶涩,但是到底是序列化丟失還是反序列化丟失?
通過對比序列化字節(jié)數(shù)組(轉(zhuǎn)成String絮识,便于查看),發(fā)現(xiàn)同樣的的bean只是amount不同绿聘,序列化的結(jié)果是一樣的,由此可以判斷Hessian序列化數(shù)據(jù)丟失

   /**
     * hessian 序列化
     * @param obj
     * @return
     */
    public static byte[] serialize(Object obj) {
        ByteArrayOutputStream bos = null;
        Hessian2Output hessianOutput = null;
        try {
            bos = new ByteArrayOutputStream();
            hessianOutput = new Hessian2Output(bos);
            hessianOutput.writeObject(obj);

            if (hessianOutput != null) {
                try {
                    hessianOutput.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return bos.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }
     /**
     * 反序列
     * @param bytes
     * @return
     */
    public static Object deserialize(byte[] bytes)  {
        ByteArrayInputStream bis = null;
        Hessian2Input hessianInput = null;
        try {
            bis = new ByteArrayInputStream(bytes);
            hessianInput = new Hessian2Input(bis);
            return hessianInput.readObject();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(bis !=null){
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(hessianInput !=null){
                try {
                    hessianInput.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }
    public static void main(String[] args) throws Exception {
        TestBean bean = new TestBean();
        bean.setAmount(new BigDecimal("20.99"))
                .setName("aaa")
                .setNum(100);

        TestBean beanZero = new TestBean();
        beanZero.setAmount(new BigDecimal("0.00"))
                .setName("aaa")
                .setNum(100);

        byte[] b1 = serialize(bean);
        byte[] b2 = serialize(beanZero);

        System.out.println("serialize Normal : "+new String(b1,"UTF-8"));
        System.out.println("serialize zero : "+new String(b2,"UTF-8"));
    }
    結(jié)果對比:
    C0/com.cloudy.chapter2.utils.HessianUtils$TestBean??num?name?amount`?d?aaaC?java.math.BigDecimal??scale?intVala?N
    C0/com.cloudy.chapter2.utils.HessianUtils$TestBean??num?name?amount`?d?aaaC?java.math.BigDecimal??scale?intVala?N

源碼分析

通過查看Hessian序列化源碼次舌,可以知道Hessian序列化對象熄攘,獲取每個對象的Field列表和FieldSerializer列表,每種類型都有自己的序列化Serializer彼念,比如:ObjectFieldSerializer挪圾。通過XXSerializer序列化具體類型。

 FieldSerializer []fieldSerializers = _fieldSerializers;
      int length = fieldSerializers.length;
      
      for (int i = 0; i < length; i++) {
        fieldSerializers[i].serialize(out, obj);
      }

TestBean的BigDecimal字段序列化方式就是ObjectFieldSerializer逐沙,這種序列化方式會獲取對象的非靜態(tài)和非transient字段哲思。而BigDecimal滿足的序列化屬性只有intVal和scale,new BigDecimal("20.99")對象的這兩個值intVal=null,scale=2,這個兩個字段無法表示一個BigDecimal對象吩案。所以以這種方式序列化BigDecimal都會是0.00棚赔,這應(yīng)該是Hessian的一個bug。

private final BigInteger intVal; 
private final int scale; 
private transient int precision;
private transient String stringCache;
/**
* If the absolute value of the significand of this BigDecimal is
* less than or equal to {@code Long.MAX_VALUE}, the value can be
* compactly stored in this field and used in computations.
*/
private final transient long intCompact;

解決方案

查看高版本代碼4.0.60徘郭,發(fā)現(xiàn)BigDecimal的序列化方式已改成StringValueSerializer序列化方式靠益,高版本增加從jar的META-INF/hessian目錄中deserializers和serializers加載配置的序列化和反序列化方式,其中java.math.BigDecimal=com.caucho.hessian.io.StringValueSerializer就存在該配置中残揉。
dubbo中也使用了hessian,但是dubbo不存在BigDecimal序列化丟失的問題胧后,查看dubbo源碼發(fā)現(xiàn),dubbo中的BigDecimal序列化使用也是StringValueSerializer抱环。

#SerializerFactory
_staticSerializerMap.put(BigDecimal.class, new StringValueSerializer());
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末壳快,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子镇草,更是在濱河造成了極大的恐慌眶痰,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件陶夜,死亡現(xiàn)場離奇詭異凛驮,居然都是意外死亡,警方通過查閱死者的電腦和手機条辟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進店門黔夭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來宏胯,“玉大人,你說我怎么就攤上這事本姥〖缗郏” “怎么了?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵婚惫,是天一觀的道長氛赐。 經(jīng)常有香客問我,道長先舷,這世上最難降的妖魔是什么艰管? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮蒋川,結(jié)果婚禮上牲芋,老公的妹妹穿的比我還像新娘。我一直安慰自己捺球,他們只是感情好缸浦,可當我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著氮兵,像睡著了一般裂逐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上泣栈,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天卜高,我揣著相機與錄音,去河邊找鬼秩霍。 笑死篙悯,一個胖子當著我的面吹牛蚁阳,可吹牛的內(nèi)容都是我干的铃绒。 我是一名探鬼主播,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼螺捐,長吁一口氣:“原來是場噩夢啊……” “哼颠悬!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起定血,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤赔癌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后澜沟,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體灾票,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年茫虽,在試婚紗的時候發(fā)現(xiàn)自己被綠了刊苍。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片既们。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖正什,靈堂內(nèi)的尸體忽然破棺而出啥纸,到底是詐尸還是另有隱情,我是刑警寧澤婴氮,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布斯棒,位于F島的核電站,受9級特大地震影響主经,放射性物質(zhì)發(fā)生泄漏荣暮。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一罩驻、第九天 我趴在偏房一處隱蔽的房頂上張望渠驼。 院中可真熱鬧,春花似錦鉴腻、人聲如沸迷扇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蜓席。三九已至,卻和暖如春课锌,著一層夾襖步出監(jiān)牢的瞬間厨内,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工渺贤, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留雏胃,地道東北人。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓志鞍,卻偏偏與公主長得像瞭亮,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子固棚,可洞房花燭夜當晚...
    茶點故事閱讀 44,864評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 概念 Java中號稱一切皆是對象统翩,在Java程序運行過程中,都是借助對象來完成一系列我們想要的操作此洲。但是對象...
    still_loving閱讀 2,132評論 0 1
  • 0 準備 安裝注冊中心:Zookeeper厂汗、Dubbox自帶的dubbo-registry-simple;安裝Du...
    七寸知架構(gòu)閱讀 13,989評論 0 88
  • JAVA序列化機制的深入研究 對象序列化的最主要的用處就是在傳遞,和保存對象(object)的時候,保證對象的完整...
    時待吾閱讀 10,863評論 0 24
  • 在這個傳統(tǒng)造物的亂世呜师,我們需要做的就是將這現(xiàn)存的一切散相娶桦,整合拼接揉化成新的外型,使中國內(nèi)在的蘊含道理,在歷史與現(xiàn)...
    公社群眾閱讀 303評論 0 0
  • 翟湘蕓焦點網(wǎng)絡(luò)第九期2018年9月4日堅持原創(chuàng)分享:…186天衷畦。今天第一節(jié)給十班上課氮双,原以為前天布置的準備性作業(yè),...
    香花盛開閱讀 99評論 0 0