zoukankan      html  css  js  c++  java
  • 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;
    }

    @Override
    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();
    }
    }

    @Override
    public <T> T decode(byte[] bytes, Class<T> clazz) {
    if (bytes == null || bytes.length == 0) {
    return null;
    }
    try {
    Constructor<T> constructor = clazz.getConstructor();
    constructor.setAccessible(true);
    T message = constructor.newInstance();
    Schema<T> schema = getSchema(clazz);
    ProtostuffIOUtil.mergeFrom(bytes, message, schema);
    return message;
    } catch (Exception e) {
    throw new IllegalStateException(e.getMessage(), e);
    }
    }

    }
    Codec接口
    /**
    * 编解码器
    * @author jiujie
    * @version $Id: Codec.java, v 0.1 2016年3月31日 上午11:39:14 jiujie Exp $
    */
    public interface Codec {

    /**
    * 编解码器ID,用于标识编解码器
    * @author jiujie
    * 2016年3月31日 上午11:38:39
    * @return
    */
    public short getId();

    /**
    * 把对象数据结构编码成一个DataBuffer
    * @param <T>
    */
    public <T> byte[] encode(T obj);

    /**
    * 把DataBuffer解包构造一个对象
    * @param <T>
    */
    public <T> T decode(byte[] bytes, Class<T> clazz);

    修改后的代码
    import java.sql.Timestamp;
    import java.util.concurrent.ConcurrentHashMap;

    import io.protostuff.LinkedBuffer;
    import io.protostuff.ProtostuffIOUtil;
    import io.protostuff.Schema;
    import io.protostuff.runtime.DefaultIdStrategy;
    import io.protostuff.runtime.Delegate;
    import io.protostuff.runtime.RuntimeEnv;
    import io.protostuff.runtime.RuntimeSchema;

    /**
    * ProtoBuffer编解码
    * @author jiujie
    * @version $Id: ProtobufferCodec.java, v 0.1 2016年7月20日 下午1:52:41 jiujie Exp $
    */
    public class ProtobufferCodec implements Codec {

    /** 时间戳转换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 ProtobufferCodec() {
    }

    @Override
    public short getId() {
    return Codecs.PROTOBUFFER_CODEC;
    }

    @SuppressWarnings("unchecked")
    public static <T> Schema<T> getSchema(Class<T> clazz) {
    Schema<T> schema = (Schema<T>) cachedSchema.get(clazz);
    if (schema == null) {
    schema = RuntimeSchema.createFrom(clazz, idStrategy);
    cachedSchema.put(clazz, schema);
    }
    return schema;
    }

    @Override
    public <T> byte[] encode(T obj) {
    if (obj == null) {
    return null;
    }
    @SuppressWarnings("unchecked")
    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();
    }
    }

    @Override
    public <T> T decode(byte[] bytes, Class<T> clazz) {
    if (bytes == null || bytes.length == 0) {
    return null;
    }
    try {
    Schema<T> schema = getSchema(clazz);
    //改为由Schema来实例化解码对象,没有构造函数也没有问题
    T message = schema.newMessage();
    ProtostuffIOUtil.mergeFrom(bytes, message, schema);
    return message;
    } catch (Exception e) {
    throw new IllegalStateException(e.getMessage(), e);
    }
    }

    }

    TimestampDelegate类

    import java.io.IOException;
    import java.sql.Timestamp;

    import io.protostuff.Input;
    import io.protostuff.Output;
    import io.protostuff.Pipe;
    import io.protostuff.WireFormat.FieldType;
    import io.protostuff.runtime.Delegate;

    /**
    * protostuff timestamp Delegate
    * @author jiujie
    * @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,
    boolean repeated) throws IOException {
    output.writeFixed64(number, input.readFixed64(), repeated);
    }

    }


    版权声明:本文为CSDN博主「笔下生灰」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/connect_me/article/details/51970201

  • 相关阅读:
    前台传入的application/json;charset=UTF-8格式的数据,java后端从request中获取json数据
    vue-element-admin实战 | 第二篇: 最小改动接入后台实现根据权限动态加载菜单
    vue-element-admin
    进程间通信的几种方式以及线程间通信的几种方式
    vue调用api接口解决跨域问题
    C#多态性(函数重载)
    VirtualBox中安装CentOS7后无法上网的解决方案
    C#继承
    android通过url下载文件
    python的数据爬取
  • 原文地址:https://www.cnblogs.com/duanxz/p/4494212.html
Copyright © 2011-2022 走看看