Hessian 3.2.0的两个bug

在将Hessian从3.0.13升级到3.2.0时碰到两个bug和一个ClassLoader处理策略的改变的问题,在此记录下,希望能为使用Hessian 3.2.0的同学们提供点帮助,避免再走同样的弯路。

Bug 1:HessianInput的readObject(Class)无效
对于使用Hessian 1的同学而言,有可能会使用到HessianInput的readObject(Class)这个方法,以实现将输入流反序列化为指定的类实例,这在有一个场景中是很需要的,例如序列化时序列化的是一个子类对象,但反序列化时需要反序列化为父类,这个时候就非常需要这方法了,在Hessian 3.2.0之前的版本中这个没有问题,但升级到3.2.0后就出现问题了,指定了Class会无效。
跟踪Hessian 3.2.0代码,发现它把之前版本的HessianInput的readObject(Class)方法做了改动,改为了:
    String type = readType();

      
// hessian/3386
      if ("".equals(type)) {
    Deserializer reader;
    reader 
= _serializerFactory.getDeserializer(cl);

    
return reader.readMap(this);
      }
      
else {
    Deserializer reader;
    reader 
= _serializerFactory.getObjectDeserializer(type);

        
return reader.readMap(this);
      }
从上面代码可以看出,只要序列化流中有类型信息,那么就完全忽视传入的指定的Class类型,而在hessian中貌似只有Map类型的才不会写type信息,其他都会写,所以就导致了这个地方大多数情况下都会无视传入的指定的Class类型,更让人郁闷的是,去看Hessian2Input.readObject(Class)方法,它的处理方式就是正确的,在type不为""的情况下,它的处理方式为:
Deserializer reader;
    reader 
= findSerializerFactory().getObjectDeserializer(type, cl);

    
return reader.readMap(this);
而默认的SerializerFactory的getObjectDeserializer的实现如下:
Deserializer reader = getObjectDeserializer(type);
    
    
if (cl == null
    
|| cl.equals(reader.getType())
    
|| cl.isAssignableFrom(reader.getType())
    
|| HessianHandle.class.isAssignableFrom(reader.getType())) {
      
return reader;
    }

    
if (log.isLoggable(Level.FINE)) {
      log.fine(
"hessian: expected '" + cl.getName() + "' at '" + type + "' ("
           
+ reader.getType().getName() + ")");
    }
    
    
return getDeserializer(cl);
从上面这段代码的实现来看,是可以满足传入指定的Class类型的方式的需求的。

因此修正这个BUG的方法为,继承HessianInput,并覆盖它的readObject(Class)方法,将其中type不为""的处理方式改成和Hessian2Input一样,重新测试,OK。
这个Bug即使到最新的Hessian 3.2.1里也没有修复,因此暂时仍然需要自行处理。

Bug 2:当Map中或对象中有两个long[]时反序列化出错
这个问题还真要凑巧才能碰上,大家可以自己写段简单的程序测试一下,用Hessian2Input和Hessian2Output去完成下面datas对象的序列化和反序列化:
Map<String,Object> datas=new HashMap<String,Object>();
datas.put(
"1",new long[]{1L,-1L});
datas.put(
"2",new long[]{2L,-2L});
反序列化的时候会抛出UnsupportedOperationException或java.util.Map cannot assigned from null这样的异常信息,而且如果Map中只有一个long[]数组是不会抛异常的,诡异呀,跟踪Hessian 3.2.0代码,发现有个很诡异的地方,在有两个数组后,Hessian会调用BasicDeserializer中的readLengthList方法,这个方法中竟然没有对long[]数组的处理,而只有对其他布尔型数组、短整型数组、整型数组等的处理,而当long[]数组的情况调用这个方法时,即抛出了UnsupportedOperationException异常,而更搞的是BasicDeserializer中的readList方法中是有对long[]数组的处理的,于是基本可以判断是Hessian的开发者漏写了对long[]的处理。
修正这个bug可以采用这两种方法:
1、修改BasicDeserializer,在readLengthList方法中加上对LONG_ARRAY的处理;
2、升级为Hessian 3.2.1,修复了这个bug,修复方法和1相同。

在升级到Hessian 3.2.0或3.2.1时还有个需要注意的问题,对于有些需要操作序列化时ClassLoader的同学有可能会碰到,Hessian 3.2.0以前的版本是在反序列化之前获取线程上下文ClassLoader来获取Class的,但在3.2.0+后,改变了这个策略,改为了在SerializerFactory实例化的时候就去获取线程上下文ClassLoader,以后在反序列化时就不再去获取了,这个方式对于需要控制ClassLoader的同学来说会有点麻烦,但还好Hessian还提供了一个方式,就是允许在创建SerializerFactory对象时传入ClassLoader,这就爽了,不用像以前一样需要通过控制线程上下文ClassLoader了,这种方式更为优雅,值得推荐。

posted on 2009-08-06 11:19 BlueDavy 阅读(9103) 评论(0)  编辑  收藏 所属分类: Java


只有注册用户登录后才能发表评论。


网站导航:
博客园   IT新闻   Chat2DB   C++博客   博问  
 

公告

 









feedsky
抓虾
google reader
鲜果

导航

<2009年8月>
2627282930311
2345678
9101112131415
16171819202122
23242526272829
303112345

统计

随笔分类

随笔档案

文章档案

Blogger's

搜索

最新评论

阅读排行榜

评论排行榜