天天看点

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);