未来小站


  • 首页

  • 标签

  • 归档

Dubbo Hessian2序列化问题

发表于 2017-12-22

问题

定义了一个接口,返回值为Map<String, Byte>,consumer收到结果后,使用Byte value = map.get(key)获取结果,抛出了如下类型转换异常:
如下:

1
2
3
4
5
6
7

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

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)

当时很奇怪,为什么返回值已经是Map<String, Byte>了,还会抛类型转换异常呢。

分析

首先想到的是通过debug确认返回的类型是否是Byte,设置断点后发现返回的Map的value的类型并不是Byte而是Integer,那么为什么会是Integer呢?
这里猜测这里很可能是dubbo序列化导致的,dubbo默认使用Hessaian2作为序列化协议,所以去看了下Hessian2的序列化实现,果不其然,byte会被反序列化成Integer

代码在Hessian2Input的readObject方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

/**
* Reads an arbitrary object from the input stream when the type
* is unknown.
*/
public Object readObject()
throws IOException
{
int tag = _offset < _length ? (_buffer[_offset++] & 0xff) : read();

switch (tag) {
case 'N':
return null;

case 'T':
return Boolean.valueOf(true);

case 'F':
return Boolean.valueOf(false);

// direct integer
case 0x80: case 0x81: case 0x82: case 0x83:
case 0x84: case 0x85: case 0x86: case 0x87:
case 0x88: case 0x89: case 0x8a: case 0x8b:
case 0x8c: case 0x8d: case 0x8e: case 0x8f:

case 0x90: case 0x91: case 0x92: case 0x93:
case 0x94: case 0x95: case 0x96: case 0x97:
case 0x98: case 0x99: case 0x9a: case 0x9b:
case 0x9c: case 0x9d: case 0x9e: case 0x9f:

case 0xa0: case 0xa1: case 0xa2: case 0xa3:
case 0xa4: case 0xa5: case 0xa6: case 0xa7:
case 0xa8: case 0xa9: case 0xaa: case 0xab:
case 0xac: case 0xad: case 0xae: case 0xaf:

case 0xb0: case 0xb1: case 0xb2: case 0xb3:
case 0xb4: case 0xb5: case 0xb6: case 0xb7:
case 0xb8: case 0xb9: case 0xba: case 0xbb:
case 0xbc: case 0xbd: case 0xbe: case 0xbf:
return Integer.valueOf(tag - BC_INT_ZERO);

/* byte int */
case 0xc0: case 0xc1: case 0xc2: case 0xc3:
case 0xc4: case 0xc5: case 0xc6: case 0xc7:
case 0xc8: case 0xc9: case 0xca: case 0xcb:
case 0xcc: case 0xcd: case 0xce: case 0xcf:
return Integer.valueOf(((tag - BC_INT_BYTE_ZERO) << 8) + read()); //byte转换成了Integer

//省略其他代码

为了更好说明Hessian2序列化和反序列的问题,可以使用其序列化和反序列化
测试代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

import com.alibaba.com.caucho.hessian.io.Hessian2Input;
import com.alibaba.com.caucho.hessian.io.Hessian2Output;
import com.google.common.collect.Maps;
import org.junit.Test;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Map;

public class Hessian2SerialzeTest {

@Test
public void test() throws IOException {
Map<String, Byte> map = Maps.newHashMap();
map.put("weather", (byte) 1);
byte[] bytes = serialize(map);
Map<String, Byte> object = (Map<String, Byte>) deserialize(bytes);
//这里会抛异常
Byte weather = object.get("weather");
System.out.println(weather);
}

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) throws IOException{
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;

}

}

运行该test,再一次抛出了Integer转Byte失败的异常,这就证明了我们的猜测,Hessian2序列化确实存在这个问题。
那么问题清晰了,解决就很自然了,要么换一种序列化协议,要么用Object接受Byte,然后把object强转成Byte(证实可行)。

Hello World

发表于 2017-12-19

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

rhwayfun

2 日志
2 标签
© 2017 rhwayfun
由 Hexo 强力驱动
|
主题 — NexT.Muse v5.1.3