在java中,序列化是经常需要使用的,比如对象在网络中传输,那么就必须要序列化后进行传输。而java自带的序列化使用起来虽然方便,但是它序列化后占的体积大,而且不能跨语言,因此在涉及到序列化的时候必然要找到一款高效的序列化框架。在网上查找了一下,发现protostuff使用方便,而且性能比较高,本篇博客简单记录一下ptotostuff如何实现一个序列化和反序列化。
一、需求
1、有一个用户类(Person)和一个地址类(Address),一个人有多个地址
2、person中有部分字段不需要序列化
|- 使用transient修饰即可不进行序列化
3、当对地址单独序列化时,需要定制化序列化,即有用户判断在什么情况下才可以序列化。(比如:当某个字段不可为空时才可以进行序列化)
|- 此种情况可以通过自定义Schema进行实现
4、如果后期序列化的类中新增了字段或删除了字段如何处理,参考 这篇文章, 此处不做处理。
二、实现
1、引入pom文件
<dependencyManagement> <dependencies> <dependency> <groupId>io.protostuff</groupId> <artifactId>protostuff-bom</artifactId> <version>1.4.4</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.10</version> <scope>test</scope> </dependency> <dependency> <groupId>io.protostuff</groupId> <artifactId>protostuff-api</artifactId> </dependency> <dependency> <groupId>io.protostuff</groupId> <artifactId>protostuff-core</artifactId> </dependency> <dependency> <groupId>io.protostuff</groupId> <artifactId>protostuff-runtime</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.18</version> </dependency> </dependencies>
注意:主要是引入protostuff-core和protostuff-runtime这2个依赖
2、定义Address类
@Data @Builder public class Address { private String address; private String phone; }
3、自定义Address的Schema,用于定制化开发,此处简单实现,当address=null时不可进行序列化
/** * 自定义Address的Schema,主要是用于定制化开发 * @描述 * @作者 huan * @时间 2017年12月11日 - 下午9:57:24 */ public class AddressSchema implements Schema<Address> { @Override public String getFieldName(int number) { String ret = ""; switch (number) { case 1: ret = "address"; break; case 2: ret = "phone"; default: break; } return ret; } @Override public int getFieldNumber(String name) { if ("address".equals(name)) { return 1; } else if ("phone".equals(name)) { return 2; } return 0; } @Override public boolean isInitialized(Address message) { if (null != message.getAddress()) { return true; } return false; } @Override public Address newMessage() { return Address.builder().build(); } @Override public String messageName() { return Address.class.getSimpleName(); } @Override public String messageFullName() { return Address.class.getName(); } @Override public Class<? super Address> typeClass() { return Address.class; } @Override public void mergeFrom(Input input, Address message) throws IOException { while (true) { int number = input.readFieldNumber(this); switch (number) { case 0: return; case 1: message.setAddress(input.readString()); break; case 2: message.setPhone(input.readString()); break; default: input.handleUnknownField(number, this); } } } @Override public void writeTo(Output output, Address message) throws IOException { if (message.getAddress() == null) { throw new UninitializedMessageException(message, this); } output.writeString(1, message.getAddress(), false); if (null != message.getPhone()) { output.writeString(2, message.getPhone(), false); } } }
注意:此处如果不了解,可以先了解一下protobuff,了解一下.proto文件的写法。
此处做了一个简单的判断,当address==null时,不可进行序列化
4、Person类的开发
@Data @Builder public class Person { private String name; private Integer age; private transient String password; private List<Address> address; }
注意: 1、Person类包含一个Address的列表
2、注意password字段前面有一个transient,这个表示不进行序列化
3、@Tag注解可以用于标记字段的顺序号,但是一个类中如果要用则建议都使用
4、上方是 官网 给出的一个警告,大致意思是:如果你想在一个非静态的内部类上使用@Tag注解,那么最好将这个非静态的内部类改成静态的内部类。
5、编写测试代码
6、查看结果