前言
对象的序列化和反序列化在网络应用通信过程中十分重要,而Json通常是其中最常用的一种传输格式。
就个人接触项目的序列化部分,主要分为两类。一类是十分严谨的,每个Json串都有与之映射的Java对象,通过对象进行序列化和反序列化。第二类较为灵活,通过类库手动拼写Json串。
目前正在用的服务架构中,使用第一类,通过fast-json类库,每次对需要返回的数据手动拼写json字符串。这样的做法有好也有坏。
优点在于
1. 拼凑的数据格式较为灵活,可以根据每个接口的实际需求,灵活的调整数据。
2. 不需为每个接口的返回值创建一个与之对应的java对象进行管理,可以极大减少一些重复代码的出现。
缺点在于
1. 手工拼写,很容易出现格式和语法错误。且代码中有大量的与业务逻辑无关的代码。使代码结构混乱,影响代码整洁度,出现问题很难排查。
2. 没有统一的对象进行映射,很难进行统一的管理。
个人更加喜欢第一种较为严谨的方式。即便代码可能膨胀,但通过继承等方式可以尽量避免,同时能够减少语法和格式等低级错误的出现。
一、常用Json序列化类库对比
目前市面上比较常用的集中Json序列化类库有,Jackson、Gson、FastJson。各种类库的API接口说明都很详细,且大同小异。使用上三者基本都没有难度。
主要考虑三者序列化和反序列化的效率问题。博客上都说FastJson是最快的类库。没有亲自测试,主要参考了这篇博客:
http://blog.csdn.net/accountwcx/article/details/50252657 FastJSON、Gson和Jackson性能对比
结论
- FastJSON和GsonJSON序列化的速度差不多,Jackson是最快的(用时Gson少大约600毫秒)
- 三个类库在反序列化上性能比较接近,Gson稍微差一些。
考虑系统以后的主体构成是SpringMVC + Netty 因此,大量的反序列化可能由springMVC实现,系统中更多的是使用序列化。因此,选择自己较为熟悉的Jackson。
二、代码实现
代码逻辑十分简单,类加载时初始化Jackson的相关配置。
序列化和反序列化都通过Jackson的objectMapper提供的接口实现。
/**
* Json序列化与反序列化工具
* @author 毅成
* @since 2017年7月22日 上午10:25:22
* @version MARK 0.0.1
*/
public class JsonConvertUtil {
private static ObjectMapper objectMapper = new ObjectMapper();
//设置objectMapper
static {
// 反序列化未知属性不会失败
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
// 序列化的字段包含
objectMapper.setSerializationInclusion(Include.NON_NULL);
objectMapper.setSerializationInclusion(Include.NON_EMPTY);
}
/**
* 序列化对象
* @author 毅成
* @since 2017年7月22日 上午10:25:59
* @version MARK 0.0.1
*/
public static String serializeObj(Object t){
String jsonStr = null;
try {
jsonStr = objectMapper.writeValueAsString(t);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return jsonStr;
}
/**
* 反序列化
* @author 毅成
* @since 2017年7月22日 上午10:37:45
* @version MARK 0.0.1
*/
public static <T> T deserializeJson(String jsonStr, Class<T> type){
T obj = null;
try {
obj = objectMapper.readValue(jsonStr, type);
} catch (Exception e) {
e.printStackTrace();
}
return obj;
}
public static void main(String[] args) {
int[] array = {1,2,3,4,5,6,7};
String arrStr = serializeObj(array);
System.out.println(arrStr);
int[] arrayo = deserializeJson(arrStr, int[].class);
System.out.println(arrayo);
}
}
三、关于对象序列化的补充
对象序列化在项目中很普通但也很常用。在项目运行中我们通常需要观察一些关键对象的属性和值,通过日志将其打印出来。
但是通常而言,打印会直接调用Object的toString方法打印出对象的hashCode。这样很难查询对象的详细信息。
因此,通常在代码中,也会使一些对象统一继承一个基类,重写其toString方法。实现序列化输出。
个人常用的方式是common-lang包的toStringBuilder类实现,较为简单。具体如下
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
该工具类的API还提供了一些序列化的风格。如
ToStringStyle.JSON_STYLE //Json风格
可以根据参照API根据自己的需求实现