關於資料序列化(4)自定義序列化的實現,支援常用集合框架
阿新 • • 發佈:2018-12-12
下面的示例很好的揭示瞭如何實現自定義序列化的方法。
支援byte, byte[], boolean, boolean[], int, int[], long, long[] ,double ,double[], String, String[], 以及Enum, List,Map兩種包裝型別,以及實現了ISerilizable的實體類。
稍加改造就可以在專案中應用
/**
* 分散式序列化介面
* 除了基本型別 其餘資料需要分散式傳輸必須實現本介面
* 注:實現本介面的類必須有無參建構函式!
* @see SerializeTool#write(Object, java.io.DataOutputStream)
* @see SerializeTool#read(java.io.DataInputStream)
*/
public interface ISerilizable {
public void writeTo(OutputStream out) throws IOException;
public void readFrom(InputStream in) throws IOException;
}
/**
* 支援實現{@link ISerilizable}的類,<br>
* 以及<b>byte,float,double,long</b>四種基本型別,<br>和
* <b>Collection(list和set),map</b>三種集合框架,<br>和
* <b>protobuf</b>.
* <br>
* TODO:迴圈因引用
* @author BAO
* @see #readFile(String fileName) 建立關閉FileInputStream DataInputStream
* @see #read(DataInputStream in)
* @see #readObject(DataInputStream stream) throws Exception
*
*/
public class SerializeTool {
/**
* 從流中讀取資料
* 只能順序讀 會自動進行型別轉換
* @return
*/
public static <T> T read (DataInputStream stream) {
try {
return readObject(stream);
} catch (Exception e) {
LogCore.BASE.error("read err!", e);
throw new SysException(e);
}
}
/**
* 從流中讀取資料
* 只能順序讀 會自動進行型別轉換
* @return
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
private static <T> T readObject(DataInputStream stream) throws Exception {
Object result = null;
//型別碼
int wireFormat = stream.readInt();
//型別
int wireType = (wireFormat & ~ARRAY);
//是陣列型別
boolean isArray = (wireFormat & ARRAY) == ARRAY;
//陣列型別的長度
int arrayLen = 0;
if(isArray) {
arrayLen = stream.readInt();
}
//空物件
if(wireType == NULL) {
return null;
}
//BYTE
if(wireType == BYTE) {
if(isArray) {
//result = stream.readRawBytes(arrayLen);//TODO 這個方法要調研一下! API應該提供此方法
byte[] values = new byte[arrayLen];
for(int i = 0; i < arrayLen; i++) {
values[i] = stream.readByte();
}
result = values;
} else {
result = stream.readByte();
}
//BOOLEAN
} else if(wireType == BOOLEAN) {
if(isArray) {
boolean[] values = new boolean[arrayLen];
for(int i = 0; i < arrayLen; i++) {
values[i] = stream.readBoolean();
}
result = values;
} else {
result = stream.readBoolean();
}
//INT
} else if(wireType == INT) {
if(isArray) {
int[] values = new int[arrayLen];
for(int i = 0; i < arrayLen; i++) {
values[i] = stream.readInt();
}
result = values;
} else {
result = stream.readInt();
}
//LONG
} else if(wireType == LONG) {
if(isArray) {
long[] values = new long[arrayLen];
for(int i = 0; i < arrayLen; i++) {
values[i] = stream.readLong();
}
result = values;
} else {
result = stream.readLong();
}
//FLOAT
} else if(wireType == FLOAT) {
if(isArray) {
float[] values = new float[arrayLen];
for(int i = 0; i < arrayLen; i++) {
values[i] = stream.readFloat();
}
result = values;
} else {
result = stream.readFloat();
}
//DOUBLE
} else if(wireType == DOUBLE) {
if(isArray) {
double[] values = new double[arrayLen];
for(int i = 0; i < arrayLen; i++) {
values[i] = stream.readDouble();
}
result = values;
} else {
result = stream.readDouble();
}
//STRING
} else if(wireType == STRING) {
if(isArray) {
String[] values = new String[arrayLen];
for(int i = 0; i < arrayLen; i++) {
values[i] = stream.readUTF();
}
result = values;
} else {
result = stream.readUTF();
}
//ENUM
} else if(wireType == ENUM) {
//實際型別
String className = stream.readUTF();
String val = stream.readUTF();
//建立例項
Class cls = Class.forName(className);
result = Enum.valueOf(cls, val);
//COLLECTION LIST SET
} else if(wireType == COLLECTION || wireType == LIST || wireType == SET) {
//長度
int len = stream.readInt();
//型別
Collection list;
if(wireType == LIST) list = new ArrayList<>();
else if(wireType == SET) list = new HashSet<>();
else list = new ArrayList<>(); //未知Collection的具體實現 暫時一律使用arrayList子類的實現
//填充資料
for(int i = 0; i < len; i++) {
list.add(read(stream));
}
result = list;
//MAP
} else if(wireType == MAP) {
//長度
int len = stream.readInt();
//資料
Map map = new LinkedHashMap<>();
for(int i = 0; i < len; i++) {
Object key = read(stream);
Object val = read(stream);
map.put(key, val);
}
result = map;
//IDistributedSerilizable介面
} else if(wireType == DISTRIBUTED) {
//實際型別
/*這種方式要提前生成常量池switch case(int)
int id = stream.readInt();
ISerilizable seriable = org.gof.core.CommonSerializer.create(id);
if(seriable == null)
seriable = _commonFunc.apply(id);
seriable.readFrom(this);
result = seriable;*/
String className = stream.readUTF();
Class<?> cls = Class.forName(className);
//建立例項並載入資料
Constructor<?> constructor = cls.getDeclaredConstructor();
constructor.setAccessible(true);
ISerilizable seriable = (ISerilizable)constructor.newInstance();
seriable.readFrom(stream);
result = seriable;
//protobuf訊息
} else if(wireType == MSG) {
//Object[]
} else if(wireType == OBJECT && isArray) {
Object[] values = new Object[arrayLen];
for(int i = 0; i < arrayLen; i++) {
values[i] = read(stream);
}
result = values;
//其餘一律不支援
} else {
throw new SysException("發現無法被反序列化的型別: wireType={}, isArray={}", wireType, isArray);
}
//返回值
return (T) result;
}
/*write*/
public static <T> T deserilize(byte[] data){
ByteArrayInputStream in = new ByteArrayInputStream(data);
DataInputStream stream = new DataInputStream(in);
return read(stream);
}
/**
* 連續讀取Object到list
*/
public static <T> List<T> deserilize2List(byte[] data){
return deserilize2List(data, new ArrayList<>());
}
public static <T> List<T> deserilize2List(byte[] data, List<T> list){
try (ByteArrayInputStream in = new ByteArrayInputStream(data);
DataInputStream stream = new DataInputStream(in)){
while(stream.available() > 0){
T t = read(stream);
list.add(t);
}
return list;
} catch (Exception e) {
LogCore.BASE.error("read file err:{}", e);
return null;
}
}
public static byte[] serlize(Object value) throws IOException {
try(ByteArrayOutputStream bout = new ByteArrayOutputStream();
DataOutputStream stream = new DataOutputStream(bout)) {
writeObject(value, stream);
return bout.toByteArray();
} catch (Exception e) {
throw new SysException(e, "OutputStream寫入資料失敗。");
}
}
/**
* 寫入資料到流中
* 僅支援
* byte byte[] boolean boolean[] int int[] long long[]
* double double[] String String[]
* Enum列舉 List、Map兩種包裝型別
* 以及實現了IDistributedSerilizable介面的類
* @param value
* @throws IOException
*/
public static void write(Object value, DataOutputStream stream) {
try {
writeObject(value, stream);
//不支援序列化化的錯誤 要對外匯報
} catch (Exception e) {
throw new SysException(e, "OutputStream寫入資料失敗。");
}
}
/**
* 寫入資料到流中
* 僅支援
* byte byte[] boolean boolean[] int int[] long long[]
* double double[] String String[]
* Enum列舉 List、Map兩種包裝型別
* 以及實現了IDistributedSerilizable介面的類
* @param value
* @throws IOException
*/
static void writeObject(Object value, DataOutputStream stream) throws IOException {
//空物件
if(value == null) {
stream.writeInt(NULL);
}
//資料型別
Class<?> clazz = value.getClass();
//BYTE
if(clazz == byte.class || clazz == Byte.class) {
stream.writeInt(BYTE);
stream.writeByte((byte)value);
} else if(clazz == byte[].class) {
byte[] array = (byte[])value;
stream.writeInt(BYTE | ARRAY);
stream.writeInt(array.length);
stream.write(array);
//BOOLEAN
} else if(clazz == boolean.class || clazz == Boolean.class) {
stream.writeInt(BOOLEAN);
stream.writeBoolean((boolean)value);
} else if(clazz == boolean[].class) {
boolean[] array = (boolean[])value;
stream.writeInt(BOOLEAN | ARRAY);
stream.writeInt(array.length);
for(int i = 0; i < array.length; i++) {
stream.writeBoolean(array[i]);
}
//INT
} else if(clazz == int.class || clazz == Integer.class) {
stream.writeInt(INT);
stream.writeInt((int)value);
} else if(clazz == int[].class) {
int[] array = (int[])value;
stream.writeInt(INT | ARRAY);
stream.writeInt(array.length);
for(int i = 0; i < array.length; i++) {
stream.writeInt(array[i]);
}
//LONG
} else if(clazz == long.class || clazz == Long.class) {
stream.writeInt(LONG);
stream.writeLong((long)value);
} else if(clazz == long[].class) {
long[] array = (long[])value;
stream.writeInt(LONG | ARRAY);
stream.writeInt(array.length);
for(int i = 0; i < array.length; i++) {
stream.writeLong(array[i]);
}
//FLOAT
} else if(clazz == float.class || clazz == Float.class) {
stream.writeFloat(FLOAT);
stream.writeFloat((float)value);
} else if(clazz == float[].class) {
float[] array = (float[])value;
stream.writeInt(FLOAT | ARRAY);
stream.writeInt(array.length);
for(int i = 0; i < array.length; i++) {
stream.writeFloat(array[i]);
}
//DOUBLE
} else if(clazz == double.class || clazz == Double.class) {
stream.writeInt(DOUBLE);
stream.writeDouble((double)value);
} else if(clazz == double[].class) {
double[] array = (double[])value;
stream.writeInt(DOUBLE | ARRAY);
stream.writeInt(array.length);
for(int i = 0; i < array.length; i++) {
stream.writeDouble(array[i]);
}
//STRING
} else if(clazz == String.class) {
stream.writeInt(STRING);
stream.writeUTF((String)value);
} else if(clazz == String[].class) {
String[] array = (String[])value;
stream.writeInt(STRING | ARRAY);
stream.writeInt(array.length);
for(int i = 0; i < array.length; i++) {
stream.writeUTF(array[i]);
}
//ENUM
} else if(value instanceof Enum) {
Enum<?> val = (Enum<?>) value;
stream.writeInt(ENUM);
stream.writeUTF(val.getClass().getName());
stream.writeUTF(val.name());
//COLLECTION LIST SET
} else if(value instanceof Collection) {
Collection<?> val = (Collection<?>) value;
//判斷子型別
int type;
if(value instanceof List) type = LIST;
else if(value instanceof Set) type = SET;
else type = COLLECTION;
stream.writeInt(type);
stream.writeInt(val.size());
for(Object o : val) {
write(o, stream);
}
//MAP
} else if(value instanceof Map) {
Map<?,?> val = (Map<?,?>) value;
stream.writeInt(MAP);
stream.writeInt(val.size());
for(Entry<?, ?> e : val.entrySet()) {
Object k = e.getKey();
Object v = e.getValue();
write(k, stream);
write(v, stream);
}
//IDistributedSerilizable介面
} else if(value instanceof ISerilizable) {
ISerilizable seriable = (ISerilizable)value;
stream.writeInt(DISTRIBUTED);
stream.writeInt(value.getClass().getName().hashCode());
seriable.writeTo(stream);
//protobuf訊息
// } else if(value instanceof Message) {
// Message msg = (Message)value;
// byte[] bytes = msg.toByteArray();
//
// stream.writeInt32NoTag(MSG);
// stream.writeInt32NoTag(bytes.length); //訊息長度 不包括訊息型別
// stream.writeInt32NoTag(msg.getClass().getName().hashCode());
// stream.writeRawBytes(bytes);
//陣列
} else if(value instanceof Object[]) {
Object[] array = (Object[])value;
stream.writeInt(OBJECT | ARRAY);
stream.writeInt(array.length);
for(Object o : array) {
write(o, stream);
}
//其餘一律不支援
} else {
throw new SysException("發現無法被序列化的型別:{}", clazz.getName());
}
}
}
思考:如何處理迴圈引用的問題?在json的序列化和protocol的序列化中的迴圈引用是如何處理的?