msgpack是一种高效的二进制序列化格式,官方连接提供了不少中语言的实现,Java做为经常使用的开发语言之一,官方也提供了支持。</br>java
Java版的实现官方也提供了一些QuickStart教程,这里就很少说了,主要说下以前遇到的一个问题,因为某个POJO对象里含有Map<Integer, Object>类型的成员,在使用msgpack进行序列化和反序列化时,出现了一些奇怪的现象,好比反序列化出来的Map在进行get时没法表现出正常的操做,虽然Debug时看到内存里确实有数据。后来简单分析了一下发现,在没有指定模板类型时,msgpack反序列化出来的Map其实是其Jar包内本身封装的一个Map实现类,因此就会出现上述的状况,要解决这个问题,就须要在反序列化解析时,给msgpack明确指定模板类型。git
msgpack的内置提供了不少模板,其中就有MapTemplate,这是一个泛型类,在构造时须要指定key和val的模板类型,而msgpack并无内置Object的模板,因此当若是须要序列化和反序列化一个Value是Object的Map时,就会出现问题。所以咱们须要本身来实现一个Object的模板,代码以下:github
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时做为参数传递进去便可,以下面的例子 :ide
MessagePack pack = new MessagePack(); byte[] bytes = pack.write(map); Map<Integer, Object> m = pack.read(bytes, Templates.tMap(Templates.TInteger, ObjectTemplate.getInstance()));
整体来讲msgpack仍是很好用的,因此在当咱们用一个开源项目遇到问题时,先最好多看看文档和源码,不少时候就能解决咱们遇到的问题,而不是过多的抱怨测试