最近在做SSH项目应用层缓存(redis+protobuf)时,遇到一个超级蛋疼的问题,Protostuff居然不支持序列化/反序列化数组、集合等对象,版本1.5.9。开始以为版本问题,升级到最新版1.6.0,仍然不能解决问题,最后参考网友butioy的解决方案:
重新修改了工具类解决了问题,使用到的技术点:线程隔离可重用buffer缓冲区,泛型返回值,智能处理传参,使支持primitive数组,List,Set,Map实例对象的序列化和反序列化。
附上我的Protostuff 序列化/反序列化工具类java源码:
package framework.webapp.commons.utils;
import io.protostuff.LinkedBuffer;
import io.protostuff.ProtostuffIOUtil;
import io.protostuff.Schema;
import io.protostuff.runtime.RuntimeSchema;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* **************************************************
* @description Protostuff 序列化/反序列化工具类
* @author iamkarl@163.com
* @version 2.0, 2018-08-07
* @see HISTORY
* Date Desc Author Operation
* 2017-4-7 创建文件 karl create Date Desc
* Author Operation 2018-08-07 创建文件 karl Protostuff 不支持序列化/反序列化数组、集合等对象,特殊处理
* @since 2017 Phyrose Science & Technology (Kunming) Co., Ltd.
**************************************************/
public class SerializationUtil {
private static final Log log = LogFactory.getLog(SerializationUtil.class);
/**
* 线程局部变量
*/
private static final ThreadLocal<LinkedBuffer> BUFFERS = new ThreadLocal();
/**
* 序列化/反序列化包装类 Schema 对象
*/
private static final Schema<SerializeDeserializeWrapper> WRAPPER_SCHEMA = RuntimeSchema.getSchema(SerializeDeserializeWrapper.class);
/**
* 序列化对象
*
* @param obj 需要序列化的对象
* @return 序列化后的二进制数组
*/
@SuppressWarnings("unchecked")
public static byte[] serialize(Object obj) {
Class<?> clazz = (Class<?>) obj.getClass();
LinkedBuffer buffer = BUFFERS.get();
if (buffer == null) {//存储buffer到线程局部变量中,避免每次序列化操作都分配内存提高序列化性能
buffer = LinkedBuffer.allocate(512);
BUFFERS.set(buffer);
}
try {
Object serializeObject = obj;
Schema schema = WRAPPER_SCHEMA;
if (clazz.isArray() || Collection.class.isAssignableFrom(clazz)
|| Map.class.isAssignableFrom(clazz) || Set.class.isAssignableFrom(clazz)) {//Protostuff 不支持序列化/反序列化数组、集合等对象,特殊处理
serializeObject = SerializeDeserializeWrapper.builder(obj);
} else {
schema = RuntimeSchema.getSchema(clazz);
}
return ProtostuffIOUtil.toByteArray(serializeObject, schema, buffer);
} finally {
buffer.clear();
}
}
/**
* 反序列化对象
*
* @param data 需要反序列化的二进制数组
* @param clazz 反序列化后的对象class
* @param <T> 反序列化后的对象类型
* @return 反序列化后的实例对象
*/
public static <T> T deserialize(Class<T> clazz, byte[] data) {
if (clazz.isArray() || Collection.class.isAssignableFrom(clazz)
|| Map.class.isAssignableFrom(clazz) || Set.class.isAssignableFrom(clazz)) {//Protostuff 不支持序列化/反序列化数组、集合等对象,特殊处理
SerializeDeserializeWrapper<T> wrapper = new SerializeDeserializeWrapper<>();
ProtostuffIOUtil.mergeFrom(data, wrapper, WRAPPER_SCHEMA);
return wrapper.getData();
} else {
Schema<T> schema = RuntimeSchema.getSchema(clazz);
T message = schema.newMessage();
ProtostuffIOUtil.mergeFrom(data, message, schema);
return message;
}
}
/**
* <p>
* 序列化/反序列化对象包装类 专为基于 Protostuff 进行序列化/反序列化而定义。 Protostuff
* 是基于POJO进行序列化和反序列化操作。 如果需要进行序列化/反序列化的对象不知道其类型,不能进行序列化/反序列化;
* 比如Map、List、String、Enum等是不能进行正确的序列化/反序列化。
* 因此需要映入一个包装类,把这些需要序列化/反序列化的对象放到这个包装类中。 这样每次 Protostuff
* 都是对这个类进行序列化/反序列化,不会出现不能/不正常的操作出现
* </p>
*
* @author butioy
*/
static class SerializeDeserializeWrapper<T> {
private T data;
public static <T> SerializeDeserializeWrapper<T> builder(T data) {
SerializeDeserializeWrapper<T> wrapper = new SerializeDeserializeWrapper<>();
wrapper.setData(data);
return wrapper;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
public static void main(String[] args) throws Exception {
System.out.println("String[abcd]:" + SerializationUtil.serialize("abcd").length);
byte[] array = "abcd".getBytes();
Class c = String[].class;
//System.out.println(new String(SerializationUtil.deserialize(byte[].class, SerializationUtil.serialize(array))));
System.out.println("array:" + SerializationUtil.serialize(array).length);
System.out.println(SerializationUtil.deserialize(byte[].class, SerializationUtil.serialize(array)).getClass());
//System.out.println(SerializationUtil.deserialize(byte[].class, SerializationUtil.serialize(array)).getClass());
//LinkedList<Object> list = new LinkedList<>();
Set<Object> list = new HashSet<>();
list.add("aa");
list.add("bb");
System.out.println(SerializationUtil.serialize(list).length);
//System.out.println(SerializationUtil.deserialize(LinkedList.class, SerializationUtil.serialize(list)));
//System.out.println(SerializationUtil.deserialize(LinkedList.class, SerializationUtil.serialize(list)).getClass());
System.out.println(SerializationUtil.deserialize(HashSet.class, SerializationUtil.serialize(list)));
System.out.println(SerializationUtil.deserialize(HashSet.class, SerializationUtil.serialize(list)).getClass());
}
}
maven依赖:
<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-core</artifactId>
<version>1.6.0</version>
</dependency>
<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-runtime</artifactId>
<version>1.6.0</version>
</dependency>