天天看點

Protostuff自定義序列化(Delegate)解析

背景

在使用protostuff進行序列化的時候,不幸地遇到了一個問題,就是timestamp作為字段的時候,轉換出現問題,通過protostuff轉換後的結果都是1970-01-01 08:00:00,這就造成了timestamp不能夠序列化。于是google了一番,得知可以用delegate來解決這個問題。

原來的代碼

protobuffercodec類

import java.lang.reflect.constructor;

import java.util.map;

import java.util.concurrent.concurrenthashmap;

import io.protostuff.linkedbuffer;

import io.protostuff.protostuffioutil;

import io.protostuff.schema;

import io.protostuff.runtime.runtimeschema;

public class protobuffercodec implements codec {

private static map<class<?>, schema<?>> cachedschema = new concurrenthashmap<>();

public protobuffercodec() {

}

@override

public short getid() {

return codecs.protobuffer_codec;

@suppresswarnings("unchecked")

private static <t> schema<t> getschema(class<t> cls) {

schema<t> schema = (schema<t>) cachedschema.get(cls);

if (schema == null) {

schema = runtimeschema.createfrom(cls);

if (schema != null) {

cachedschema.put(cls, schema);

return schema;

public <t> byte[] encode(t obj) {

if (obj == null) {

return null;

class<t> cls = (class<t>) obj.getclass();

linkedbuffer buffer = linkedbuffer.allocate(linkedbuffer.default_buffer_size);

try {

schema<t> schema = getschema(cls);

byte[] bytes = protostuffioutil.tobytearray(obj, schema, buffer);

return bytes;

} catch (exception e) {

throw new illegalstateexception(e.getmessage(), e);

} finally {

buffer.clear();

public <t> t decode(byte[] bytes, class<t> clazz) {

if (bytes == null || bytes.length == 0) {

constructor<t> constructor = clazz.getconstructor();

constructor.setaccessible(true);

t message = constructor.newinstance();

schema<t> schema = getschema(clazz);

protostuffioutil.mergefrom(bytes, message, schema);

return message;

codec接口

/**

* 編解碼器

* @author jiujie

* @version $id: codec.java, v 0.1 2016年3月31日 上午11:39:14 jiujie exp $

*/

public interface codec {

* 編解碼器id,用于辨別編解碼器

* 2016年3月31日 上午11:38:39

* @return

public short getid();

* 把對象資料結構編碼成一個databuffer

* @param <t>

public <t> byte[] encode(t obj);

* 把databuffer解包構造一個對象

public <t> t decode(byte[] bytes, class<t> clazz);

修改後的代碼

import java.sql.timestamp;

import io.protostuff.runtime.defaultidstrategy;

import io.protostuff.runtime.delegate;

import io.protostuff.runtime.runtimeenv;

* protobuffer編解碼

* @version $id: protobuffercodec.java, v 0.1 2016年7月20日 下午1:52:41 jiujie exp $

/** 時間戳轉換delegate,解決時間戳轉換後錯誤問題 @author jiujie 2016年7月20日 下午1:52:25 */

private final static delegate<timestamp> timestamp_delegate = new timestampdelegate();

private final static defaultidstrategy idstrategy = ((defaultidstrategy) runtimeenv.id_strategy);

private final static concurrenthashmap<class<?>, schema<?>> cachedschema = new concurrenthashmap<>();

static {

idstrategy.registerdelegate(timestamp_delegate);

public static <t> schema<t> getschema(class<t> clazz) {

schema<t> schema = (schema<t>) cachedschema.get(clazz);

schema = runtimeschema.createfrom(clazz, idstrategy);

cachedschema.put(clazz, schema);

//改為由schema來執行個體化解碼對象,沒有構造函數也沒有問題

t message = schema.newmessage();

timestampdelegate類

import java.io.ioexception;

import io.protostuff.input;

import io.protostuff.output;

import io.protostuff.pipe;

import io.protostuff.wireformat.fieldtype;

* protostuff timestamp delegate

* @version $id: timestampdelegate.java, v 0.1 2016年7月20日 下午2:08:11 jiujie exp $

public class timestampdelegate implements delegate<timestamp> {

public fieldtype getfieldtype() {

return fieldtype.fixed64;

public class<?> typeclass() {

return timestamp.class;

public timestamp readfrom(input input) throws ioexception {

return new timestamp(input.readfixed64());

public void writeto(output output, int number, timestamp value,

boolean repeated) throws ioexception {

output.writefixed64(number, value.gettime(), repeated);

public void transfer(pipe pipe, input input, output output, int number,

output.writefixed64(number, input.readfixed64(), repeated);