Dubbo使用Hessian2序列化时针对Byte类型出现java.lang.ClassCastException

简介: Dubbo使用Hessian2序列化时针对Byte类型出现java.lang.ClassCastException

背景

前不久翎野君帮同事看一个问题,比较有启发性,特记录一下。一个dubbo rpc方法中,从请求对象中取出Set<Byte>变量进行循环操作,然后出现下面的问题。

java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Byte

乍一看还有些费解,好好的代码,看上去那么的乖巧可爱,怎么会突然冒出来这个问题,带着怀疑的态度自己本地编写了Test方法试验了一下,发现也没有问题。然后就把目光放在dubbo传输框架上面了,查阅了一些资料,发现dubbo默认的hessian2序列化协议不支持Byte类型。

问题复现

package com.lingyejun.test;
import com.alibaba.com.caucho.hessian.io.Hessian2Input;
import com.alibaba.com.caucho.hessian.io.Hessian2Output;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class HessianTest {
    @Test
    public void test() throws IOException {
        Byte basicByte = 88;
        byte[] basicByteArray = serialize(basicByte);
        // 序列化后得到的是Integer类型的变量
        Object obj = deserialize(basicByteArray);
        // 会报类型转换错误
        Byte desB = (Byte) obj;
        Set<Byte> byteSet = new HashSet<>();
        byteSet.add((byte) 11);
        byteSet.add((byte) 6);
        byte[] byteSetArray = serialize(byteSet);
        Set<Byte> dsByteSet = (Set<Byte>) deserialize(byteSetArray);
        // 会报类型转换错误
        for (Byte aByte : dsByteSet) {
            System.out.println(aByte);
        }
        Map<Byte, Byte> byteMap = new HashMap<>();
        byteMap.put((byte) 2, (byte) 3);
        byte[] byteMapArray = serialize(byteMap);
        Map<Byte, Byte> dsByteMap = (Map<Byte, Byte>) deserialize(byteMapArray);
        // 会报类型转换错误
        Byte value = dsByteMap.get(2);
        System.out.println(value);
    }
    public static byte[] serialize(Object obj) throws IOException {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        Hessian2Output ho = new Hessian2Output(os);
        byte[] cc = null;
        try {
            if (obj == null) throw new NullPointerException();
            ho.writeObject(obj);
            ho.flushBuffer();
            cc = os.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            ho.close();
        }
        return cc;
    }
    public static Object deserialize(byte[] by) {
        try {
            if (by == null) throw new NullPointerException();
            ByteArrayInputStream is = new ByteArrayInputStream(by);
            Hessian2Input hi = new Hessian2Input(is);
            return hi.readObject();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

过程

hessian2官方文档:http://hessian.caucho.com/doc/hessian-serialization.html

Hessian 的对象序列化机制有 8 种原始类型:

  • 原始二进制数据
  • boolean
  • 64-bit date(64 位毫秒值的日期)
  • 64-bit double
  • 32-bit int
  • 64-bit long
  • null
  • UTF-8 编码的 string

我们发现基础类型中并不支持Byte类型,让我们在通过源码验证一下。

在序列化时将Byte、Shor、Integer统一按照int类型进行写流。

在反序列化的过程中将byte int 按照Integer类型进行读取

警示

在使用Hessian协议对Byte类型进行序列化操作时会发生类型转化的问题,故而Byte及相关集合类如Set<Byte>、List<Byte>、Map<Byte, Byte>等尽量避免使用。

 

本篇文章如有帮助到您,请给「翎野君」点个赞,感谢您的支持。

原文链接:https://www.cnblogs.com/lingyejun/p/15586083.html

目录
打赏
0
0
0
0
12
分享
相关文章
|
22天前
|
java变量与数据类型:整型、浮点型与字符类型
### Java数据类型全景表简介 本文详细介绍了Java的基本数据类型和引用数据类型,涵盖每种类型的存储空间、默认值、取值范围及使用场景。特别强调了`byte`、`int`、`long`、`float`、`double`等基本类型在不同应用场景中的选择与优化,如文件流处理、金融计算等。引用数据类型部分则解析了`String`、数组、类对象、接口和枚举的内存分配机制。
49 15
|
22天前
|
课时11:Java数据类型划分(浮点类型)
课时11介绍了Java中的浮点数据类型。主要内容包括:1. 定义小数,默认使用Double类型;2. 定义Float变量,需在数值后加&quot;F&quot;或&quot;f&quot;进行强制转换;3. 观察不同类型计算结果,如Int型除法会丢失精度,需至少包含一个Double或Float类型以确保准确性。总结指出,在复杂计算中推荐使用Double类型以避免精度损失。
|
22天前
|
课时10:Java数据类型划分(整型类型)
本文主要围绕Java中整型数据展开,详细讲解整型变量、常量的概念,整型数据运算规则,包括数据溢出问题及解决方法,数据类型转换(自动转换与强制转换)的原理和注意事项,同时介绍了整型数据默认值的相关知识,以及byte数据类型与int数据类型的关系和使用场景,帮助读者全面掌握Java整型数据的相关内容。
Java泛型类型擦除以及类型擦除带来的问题
本文主要讲解Java中的泛型擦除机制及其引发的问题与解决方法。泛型擦除是指编译期间,Java会将所有泛型信息替换为原始类型,并用限定类型替代类型变量。通过代码示例展示了泛型擦除后原始类型的保留、反射对泛型的破坏以及多态冲突等问题。同时分析了泛型类型不能是基本数据类型、静态方法中无法使用泛型参数等限制,并探讨了解决方案。这些内容对于理解Java泛型的工作原理和避免相关问题具有重要意义。
聊聊 Go 语言中的 JSON 序列化与 js 前端交互类型失真问题
在Web开发中,后端与前端的数据交换常使用JSON格式,但JavaScript的数字类型仅能安全处理-2^53到2^53间的整数,超出此范围会导致精度丢失。本文通过Go语言的`encoding/json`包,介绍如何通过将大整数以字符串形式序列化和反序列化,有效解决这一问题,确保前后端数据交换的准确性。
92 4
Java 中 Set 类型的使用方法
【10月更文挑战第30天】Java中的`Set`类型提供了丰富的操作方法来处理不重复的元素集合,开发者可以根据具体的需求选择合适的`Set`实现类,并灵活运用各种方法来实现对集合的操作和处理。
Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面
本文探讨了Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面,帮助开发者提高代码质量和程序的健壮性。
129 2
Java泛型类型擦除以及类型擦除带来的问题
泛型擦除是指Java编译器在编译期间会移除所有泛型信息,使所有泛型类型在运行时都变为原始类型。例如,`List&lt;String&gt;` 和 `List&lt;Integer&gt;` 在JVM中都视为 `List`。因此,通过 `getClass()` 比较两个不同泛型类型的 `ArrayList` 实例会返回 `true`。此外,通过反射调用 `add` 方法可以向 `ArrayList&lt;Integer&gt;` 中添加字符串,进一步证明了泛型信息在运行时被擦除。
103 2
Java“不能转换的类型”解决
在Java编程中,“不能转换的类型”错误通常出现在尝试将一个对象强制转换为不兼容的类型时。解决此问题的方法包括确保类型间存在继承关系、使用泛型或适当的设计模式来避免不安全的类型转换。
757 7
Java“返回类型为 void 的方法不能返回一个值”解决
在 Java 中,如果一个方法的返回类型被声明为 void,那么该方法不应该包含返回值的语句。如果尝试从这样的方法中返回一个值,编译器将报错。解决办法是移除返回值语句或更改方法的返回类型。
416 5