hessian 序列化BigDecimal问题

hessian处理BigDecimal时,默认将BigDecimal作为Object对象处理,尝试将BigDecimal的各个字段序列化,会导致传输到客户端的BigDecimal位0。

目前有三种解决方案:

  • 对hessian重新打包
  • 实现目标对象的序列化和序列化接口
  • 添加自定义的AbstractSerializerFactory

对hessian重新打包

创建META-INF/hessian/serializers文件,在该文件中添加:

1
java.math.BigDecimal=com.caucho.hessian.io.StringValueSerializer

创建META-INF/hessian/deserializers文件,在该文件中添加:

1
java.math.BigDecimal=com.caucho.hessian.io.BigDecimalDeserializer

指定使用StringValueSerializer序列化BigDecimal对象,使用BigDecimalDeserializer反序列化BigDecimal对象。

实现目标对象的序列化和序列化接口

实现目标对象的序列化(com.caucho.hessian.io.Serializer)和反序列化接口(com.caucho.hessian.io.Deserializer)。

  • 序列化的类名必须为 cl.getName() + "HessianSerializer"
  • 反序列化的类名必须为 cl.getName() + "HessianDeserializer"
  • 同时必须和目标类的包路径完全一致。

添加自定义的AbstractSerializerFactory

实现自己的序列化工厂类,并添加到默认的序列化工厂中。有三处改动:

  • 自定义AbstractSerializerFactory

    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
    package com.cloudin.hessian.support;

    import com.caucho.hessian.io.*;

    import java.math.BigDecimal;
    import java.util.HashMap;
    import java.util.Map;

    /**
    * Created by YFHan on 2017/6/15 0015.
    */
    public class MyAbstractSerializerFactory extends AbstractSerializerFactory {

    private Map<String, Serializer> serializerMap = new HashMap<>();
    private Map<String, Deserializer> deserializerMap = new HashMap<>();

    public MyAbstractSerializerFactory() {
    serializerMap.put(BigDecimal.class.getName(), new StringValueSerializer());
    deserializerMap.put(BigDecimal.class.getName(), new BigDecimalDeserializer());
    }

    @Override
    public Serializer getSerializer(Class cl) throws HessianProtocolException {
    return serializerMap.get(cl.getName());
    }

    @Override
    public Deserializer getDeserializer(Class cl) throws HessianProtocolException {
    return deserializerMap.get(cl.getName());
    }
    }

  • 自定义HessianServlet

    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
    package com.cloudin.hessian.support;

    import com.caucho.hessian.io.*;
    import com.caucho.hessian.server.HessianServlet;

    import javax.servlet.ServletException;
    import java.math.BigDecimal;
    import java.util.HashMap;
    import java.util.Map;

    /**
    * 自定义HessianServlet
    * Created by YFHan on 2017/6/12 0012.
    */
    public class MyHessianServlet extends HessianServlet {

    private SerializerFactory serializerFactory;

    @Override
    public void init(javax.servlet.ServletConfig config) throws ServletException {
    super.init(config);
    serializerFactory = super.getSerializerFactory();
    serializerFactory.addFactory(new MyAbstractSerializerFactory());
    }

    @Override
    public SerializerFactory getSerializerFactory() {
    return serializerFactory;
    }
    }

  • HessianProxyFactory中添加自定义的序列化工厂实例

    1
    2
    HessianProxyFactory hessianProxyFactory = new HessianProxyFactory();
    hessianProxyFactory.getSerializerFactory().addFactory(new MyAbstractSerializerFactory());

总结

  • 第一种方案,不需要写任何代码,但是需要自己维护hessian的打包
  • 第二种方案,自定义程度很高,但是需要对hessian的序列化协议非常了解,但是工作量很大,一般不用
  • 第三种方案和第一种方案原理一致,虽然需要些代码,但是这些代码可以抽出作为团队公共代码,基本不需要跟随hessian版本升级而做出改动,同时如果有需要,可以随时添加自定义的序列化方式。

个人比较推荐第三种方式。

java hessian BigDecimal