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);
} }
使用方法场景,及注意事项
使用方法:
实现Delegage接口,并在IdStrategy策略类中注册该Delegate。
使用场景:
当需要序列化的类的字段中有transient声明序列化时会过滤字段,导致还原时丢失信息的场景,或者一些需要高度自定义数据格式的场景下,可以使用Delegate来序列化与反序列化。
注意事项:
这个对象必须是另一个对象的字段时,这个Delegate才会生效,如果直接用Timestamp来转换,则还是不生效,这个问题与源码的实现有关,源码是检测对象的字段来调用Delegate的,如果本身直接过来序列化的时候,则不会触发Delegate。
Protostuff自定义序列化(Delegate)解析的更多相关文章
- Spring源码学习-容器BeanFactory(四) BeanDefinition的创建-自定义标签的解析.md
写在前面 上文Spring源码学习-容器BeanFactory(三) BeanDefinition的创建-解析Spring的默认标签对Spring默认标签的解析做了详解,在xml元素的解析中,Spri ...
- Spring 系列教程之自定义标签的解析
Spring 系列教程之自定义标签的解析 在之前的章节中,我们提到了在 Spring 中存在默认标签与自定义标签两种,而在上一章节中我们分析了 Spring 中对默认标签的解析过程,相信大家一定已经有 ...
- fastjson自定义序列化竟然有这么多姿势?
本文介绍下fastjson自定义序列化的各种操作. 一.什么是fastjson? fastjson是阿里巴巴的开源JSON解析库,它可以解析JSON格式的字符串,支持将Java Bean序列化为JSO ...
- Spring源码阅读笔记05:自定义xml标签解析
在上篇文章中,提到了在Spring中存在默认标签与自定义标签两种,并且详细分析了默认标签的解析,本文就来分析自定义标签的解析,像Spring中的AOP就是通过自定义标签来进行配置的,这里也是为后面学习 ...
- Java程序员必备:序列化全方位解析
前言 相信大家日常开发中,经常看到Java对象"implements Serializable".那么,它到底有什么用呢?本文从以下几个角度来解析序列这一块知识点~ 什么是Java ...
- Hive中自定义序列化器(带编码)
hive SerDe的简介 https://www.jianshu.com/p/afee9acba686 问题 数据文件为文本文件,每一行为固定格式,每一列的长度都是定长或是有限制范围,考虑采用hiv ...
- .Net Core 自定义序列化格式
序列化对大家来说应该都不陌生,特别是现在大量使用WEBAPI,JSON满天飞,序列化操作应该经常出现在我们的代码上. 而我们最常用的序列化工具应该就是Newtonsoft.Json,当然你用其它工具类 ...
- Android之XML序列化和解析
XML文件是一种常用的文件格式,可以用来存储与传递数据 ,本文是XML文件序列化与解析的一个简单示例 写文件到本地,并用XML格式存储 /** * 写xml文件到本地 */ private void ...
- Newtonsoft.Json高级用法 1.忽略某些属性 2.默认值的处理 3.空值的处理 4.支持非公共成员 5.日期处理 6.自定义序列化的字段名称
手机端应用讲究速度快,体验好.刚好手头上的一个项目服务端接口有性能问题,需要进行优化.在接口多次修改中,实体添加了很多字段用于中间计算或者存储,然后最终用Newtonsoft.Json进行序列化返回数 ...
随机推荐
- Qt for Mac:发布程序(widgets和quick2)
当你用Qt开发好程序后,是不是会很期待将你的成果分享给你的小伙伴 可是Qt的库并不是OS X标配的,所以我们要自己去复制库到app包里,才可以让app在其他未安装Qt的电脑上运行. 比较幸运的是,Qt ...
- hashCode() 和equals() 区别和作用
HashSet和HashMap一直都是JDK中最常用的两个类,HashSet要求不能存储相同的对象,HashMap要求不能存储相同的键. 那么Java运行时环境是如何判断HashSet中相同对象.Ha ...
- hiho #1079 : 离散化
描述 小Hi和小Ho在回国之后,重新过起了朝7晚5的学生生活,当然了,他们还是在一直学习着各种算法~ 这天小Hi和小Ho所在的学校举办社团文化节,各大社团都在宣传栏上贴起了海报,但是贴来贴去,有些海报 ...
- Linux Kernel 'dispatch_discard_io()'安全绕过漏洞
漏洞版本: Linux Kernel 漏洞描述: Bugtraq ID:60414 CVE ID:CVE-2013-2140 Linux是一款开源的操作系统. 由于不充分的检查BLKIF_OP_DIS ...
- UVA-11983-Weird Advertisement(线段树+扫描线)[求矩形覆盖K次以上的面积]
题意: 求矩形覆盖K次以上的面积 分析: k很小,可以开K颗线段树,用sum[rt][i]来保存覆盖i次的区间和,K次以上全算K次 // File Name: 11983.cpp // Author: ...
- HDU 2476 String painter(记忆化搜索, DP)
题目大意: 给你两个串,有一个操作! 操作时可以把某个区间(L,R) 之间的所有字符变成同一个字符.现在给你两个串A,B要求最少的步骤把A串变成B串. 题目分析: 区间DP, 假如我们直接想把A变成B ...
- (转载)MySQL 统计数据行数 Select Count
(转载)http://www.5idev.com/p-php_mysql_select_count.shtml 统计数据行数 SELECT COUNT() FROM 语法用于从数据表中统计数据行数. ...
- 图论(差分约束系统):POJ 1275 Cashier Employment
Cashier Employment Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 7651 Accepted: 288 ...
- 关于 NoSQL 数据库你应该了解的 10 件事
四分之一个世纪以来,关系型数据库(RDBMS)一直是主流数据库模型.但是现在非关系型数据库,“云”或者“NoSQL”数据库,正在作为一种替代数据库模型获得越来越多的占有率.本文中我们将关注非关系型 N ...
- Ring - HDU 2296(自动机+dp)
题目大意:斯蒂文想送给他女盆友一个戒指,并且他想在戒指上刻一些字,他非常了解他女盆友喜欢什么单词,比如"love""forvevr"....并且他还把女盆友喜欢 ...