讓java版msgpack支持Object類型

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仍是很好用的,因此在當咱們用一個開源項目遇到問題時,先最好多看看文檔和源碼,不少時候就能解決咱們遇到的問題,而不是過多的抱怨測試

相關文章
相關標籤/搜索