让java版msgpack支持Object类型

2016-11-25 09:44:06|?次阅读|上传:jifeng520qq【已有?条评论】发表评论

关键词:Java|来源:唯设编程网

 
让java版msgpack支持Object类型
msgpack是一种高效的二进制序列化格式,官方链接提供了很多中语言的实现,Java作为常用的开发语言之一,官方也提供了支持。</br>
 
Java版的实现官方也提供了一些QuickStart教程,这里就不多说了,主要说下之前遇到的一个问题,由于某个POJO对象里含有Map<Integer, Object>类型的成员,在使用msgpack进行序列化和反序列化时,出现了一些奇怪的现象,比如反序列化出来的Map在进行get时无法表现出正常的操作,虽然Debug时看到内存里确实有数据。后来简单分析了一下发现,在没有指定模板类型时,msgpack反序列化出来的Map实际上是其Jar包内自己封装的一个Map实现类,所以就会出现上述的情况,要解决这个问题,就需要在反序列化解析时,给msgpack明确指定模板类型。
 
msgpack的内置提供了很多模板,其中就有MapTemplate,这是一个泛型类,在构造时需要指定key和val的模板类型,而msgpack并没有内置Object的模板,所以当如果需要序列化和反序列化一个Value是Object的Map时,就会出现问题。因此我们需要自己来实现一个Object的模板,代码如下:
 
public class ObjectTemplate extends AbstractTemplate<Object> {
 
private ObjectTemplate() {
}
 
static public ObjectTemplate getInstance() {
    return instance;
}
 
static final ObjectTemplate instance = new ObjectTemplate();
 
@Override
public void write(Packer pk, Object v, boolean required) throws IOException {
    if (v == null) {
        if (required) {
            throw new MessageTypeException("Attempted to write null");
        }
        pk.writeNil();
        return;
    }
    pk.write(v);
}
 
@Override
public Object read(Unpacker u, Object to, boolean required) throws IOException {
    if (!required && u.trySkipNil()) {
        return null;
    }
 
    return toObject(u.readValue());
}
 
private static Object toObject(Value value) throws IOException {
    Converter conv = new Converter(value);
    if (value.isNilValue()) { // null
        return null;
    } else if (value.isRawValue()) { // byte[] or String or maybe Date?
        // deserialize value to String object
        RawValue v = value.asRawValue();
        return conv.read(Templates.TString);
    } else if (value.isBooleanValue()) { // boolean
        return conv.read(Templates.TBoolean);
    } else if (value.isIntegerValue()) { // int or long or BigInteger
        // deserialize value to int
        IntegerValue v = value.asIntegerValue();
        return conv.read(Templates.TInteger);
    } else if (value.isFloatValue()) { // float or double
        // deserialize value to double
        FloatValue v = value.asFloatValue();
        return conv.read(Templates.TDouble);
    } else if (value.isArrayValue()) { // List or Set
        // deserialize value to List object
        ArrayValue v = value.asArrayValue();
        List<Object> ret = new ArrayList<Object>(v.size());
        for (Value elementValue : v) {
            ret.add(toObject(elementValue));
        }
        return ret;
    } else if (value.isMapValue()) { // Map
        MapValue v = value.asMapValue();
 
 
        Map map = new HashMap<>(v.size());
        for (Map.Entry<Value, Value> entry : v.entrySet()) {
            Value key = entry.getKey();
            Value val = entry.getValue();
 
            map.put(toObject(key), toObject(val));
        }
 
        return map;
    } else {
        throw new RuntimeException("fatal error");
    }
}
}
以上代码在issue4的基础上增加了支持基本类型作为K-V的Map的嵌套,我测试了三层嵌套Map是可以的,更深层的没有去测试,不过一般使用也应该够用了。以上模板在使用msgpack进行read和write时作为参数传递进去即可,如下面的例子 :
 
        MessagePack pack = new MessagePack();
        byte[] bytes = pack.write(map);
        Map<Integer, Object> m = pack.read(bytes, Templates.tMap(Templates.TInteger, ObjectTemplate.getInstance()));
总体来说msgpack还是很好用的,所以在当我们用一个开源项目遇到问题时,先最好多看看文档和源码,很多时候就能解决我们遇到的问题。
发表评论0条 】
网友评论(共?条评论)..
让java版msgpack支持Object类型