Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.zakgof.serialize.ZeSerializer Maven / Gradle / Ivy
package com.zakgof.serialize;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.objenesis.Objenesis;
import org.objenesis.ObjenesisStd;
import com.annimon.stream.Collectors;
import com.annimon.stream.IntStream;
import com.annimon.stream.Stream;
import com.annimon.stream.function.Consumer;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.zakgof.tools.io.ISimpleSerializer;
import com.zakgof.tools.io.SimpleBooleanSerializer;
import com.zakgof.tools.io.SimpleByteArraySerializer;
import com.zakgof.tools.io.SimpleByteSerializer;
import com.zakgof.tools.io.SimpleClassSerializer;
import com.zakgof.tools.io.SimpleDateSerializer;
import com.zakgof.tools.io.SimpleDoubleSerializer;
import com.zakgof.tools.io.SimpleEnumSerializer;
import com.zakgof.tools.io.SimpleFloatSerializer;
import com.zakgof.tools.io.SimpleInputStream;
import com.zakgof.tools.io.SimpleIntegerSerializer;
import com.zakgof.tools.io.SimpleLongSerializer;
import com.zakgof.tools.io.SimpleOutputStream;
import com.zakgof.tools.io.SimpleShortSerializer;
import com.zakgof.tools.io.SimpleStringSerializer;
@SuppressWarnings("rawtypes")
public class ZeSerializer implements ISerializer {
// public static final String COMPATIBLE_POJOS = "compatible.pojos";
public static final String FORCED_HEADER = "forced.header";
public static final String USE_OBJENESIS = "use.objenesis";
private Map parameters;
private Map knownObjects = new HashMap<>();
private List knownObjectList = new ArrayList<>();
private static final Objenesis objenesis = new ObjenesisStd();
public ZeSerializer(Map parameters) {
this.parameters = parameters;
}
public ZeSerializer() {
this(new HashMap<>());
}
@Override
public byte[] serialize(Object object) {
// long start = System.currentTimeMillis();
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream(256);
serialize(object, baos);
return baos.toByteArray();
} catch (IOException e) {
throw new ZeSerializerException(e);
} finally {
// long end = System.currentTimeMillis();
// Log.w("perf", "serialize " + object.getClass().getSimpleName() +
// " in "
// + (end-start));
}
}
public void serialize(Object object, OutputStream os) throws IOException {
try {
SimpleOutputStream sos = new SimpleOutputStream(os);
boolean hoHeader = parameters.containsKey(FORCED_HEADER) ? false : true;
fieldSerializer.write(object, object.getClass(), sos, hoHeader);
} finally {
knownObjectList.clear();
knownObjects.clear();
}
}
@SuppressWarnings("unchecked")
@Override
public T deserialize(InputStream is, Class clazz) {
// long start = System.currentTimeMillis();
try {
SimpleInputStream sis = new SimpleInputStream(is);
boolean hoHeader = parameters.containsKey(FORCED_HEADER) ? false : true;
return (T) fieldSerializer.read(sis, clazz, hoHeader);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
// long end = System.currentTimeMillis();
// Log.w("perf", "deserialize " + clazz.getSimpleName() + " in " +
// (end-start));
knownObjectList.clear();
knownObjects.clear();
}
}
public static List getAllFields(Class> type) {
List fields = new ArrayList<>();
Field[] declaredFields = type.getDeclaredFields();
Arrays.sort(declaredFields, new Comparator() {
@Override
public int compare(Field f1, Field f2) {
return f1.getName().compareTo(f2.getName());
}
});
for (Field field : declaredFields) {
if ((field.getModifiers() & (Modifier.STATIC | Modifier.TRANSIENT)) == 0)
fields.add(field);
}
if (type.getSuperclass() != null)
fields.addAll(getAllFields(type.getSuperclass()));
return fields;
}
private interface IFieldSerializer {
void write(Object object, Class> clazz, SimpleOutputStream sos) throws IOException;
Object read(SimpleInputStream sis, Class> clazz) throws IOException;
}
private interface ICompositeSerializer {
void write(T object, Class extends T> clazz, SimpleOutputStream sos, IFieldSerializer fieldSerializer) throws IOException;
T read(SimpleInputStream sis, Class extends T> clazz, IFieldSerializer fieldSerializer, Consumer rememberer) throws IOException;
}
private final FieldSerializer fieldSerializer = new FieldSerializer();
private final IFieldSerializer arraySerializer = new ArraySerializer();
private final PojoSerializer pojoSerializer = new PojoSerializer();
private final static Map, ISimpleSerializer>> serializers = new HashMap<>();
private final static Map, ICompositeSerializer>> compositeSerializers = new HashMap<>();
private final static BiMap classes = HashBiMap.create();
static {
serializers.put(byte.class, SimpleByteSerializer.INSTANCE);
serializers.put(short.class, SimpleShortSerializer.INSTANCE);
serializers.put(int.class, SimpleIntegerSerializer.INSTANCE);
serializers.put(long.class, SimpleLongSerializer.INSTANCE);
serializers.put(float.class, SimpleFloatSerializer.INSTANCE);
serializers.put(double.class, SimpleDoubleSerializer.INSTANCE);
serializers.put(boolean.class, SimpleBooleanSerializer.INSTANCE);
serializers.put(Byte.class, SimpleByteSerializer.INSTANCE);
serializers.put(Short.class, SimpleShortSerializer.INSTANCE);
serializers.put(Integer.class, SimpleIntegerSerializer.INSTANCE);
serializers.put(Long.class, SimpleLongSerializer.INSTANCE);
serializers.put(Float.class, SimpleFloatSerializer.INSTANCE);
serializers.put(Double.class, SimpleDoubleSerializer.INSTANCE);
serializers.put(Boolean.class, SimpleBooleanSerializer.INSTANCE);
serializers.put(String.class, SimpleStringSerializer.INSTANCE);
serializers.put(Date.class, SimpleDateSerializer.INSTANCE);
serializers.put(byte[].class, SimpleByteArraySerializer.INSTANCE);
serializers.put(Class.class, SimpleClassSerializer.INSTANCE);
compositeSerializers.put(HashMap.class, new HashMapSerializer());
compositeSerializers.put(ArrayList.class, new CollectionSerializer>());
compositeSerializers.put(HashSet.class, new CollectionSerializer>());
classes.put("java.util.HashMap", (byte) 1);
classes.put("java.util.ArrayList", (byte) 2);
classes.put("java.util.RegularEnumSet", (byte) 3);
classes.put("java.util.LinkedList", (byte) 4);
classes.put("java.util.HashSet", (byte) 5);
classes.put("java.util.TreeMap", (byte) 6);
classes.put("java.util.TreeSet", (byte) 7);
}
private Object instantiate(Class extends Object> clazz, Object outer) throws Exception {
Object instance = createObject(clazz, outer);
if (!clazz.isPrimitive()) {
rememberObject(instance);
}
return instance;
}
private void rememberObject(Object instance) {
if (!knownObjects.containsKey(new Wrap(instance))) {
knownObjectList.add(instance);
knownObjects.put(new Wrap(instance), knownObjectList.size() - 1);
}
}
private Object createObject(Class extends Object> clazz, Object outer) throws ReflectiveOperationException, SecurityException {
if (objenesis != null)
return objenesis.getInstantiatorOf(clazz).newInstance();
return clazz.newInstance();
}
private static Object instantiateUsingNoArgCtor(Class> clazz) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Constructor extends Object> noArgConsructor = clazz.getDeclaredConstructor();
noArgConsructor.setAccessible(true);
return noArgConsructor.newInstance();
}
private static Class> parseClassName(String className) {
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
throw new ZeSerializerException("Cannot find class " + className);
}
}
private class PojoSerializer {
public void write(Object object, Class extends Object> clazz, SimpleOutputStream sos) throws IOException {
try {
for (Field field : getAllFields(clazz)) {
if ((field.getModifiers() & (Modifier.TRANSIENT | Modifier.STATIC)) == 0) {
field.setAccessible(true);
fieldSerializer.write(field.get(object), field.getType(), sos);
}
}
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
public Object read(SimpleInputStream sis, Class extends Object> clazz, Object outer) throws IOException {
try {
Object object = instantiate(clazz, outer);
for (Field field : getAllFields(clazz)) {
if ((field.getModifiers() & (Modifier.TRANSIENT | Modifier.STATIC)) == 0) {
field.setAccessible(true);
Object value = fieldSerializer.read(sis, field.getType());
field.set(object, value);
}
}
return object;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
private class ArraySerializer implements IFieldSerializer {
@Override
public void write(Object object, Class> clazz, SimpleOutputStream sos) throws IOException {
Object[] arr = (Object[]) object;
sos.write(arr.length);
for (int i = 0; i < arr.length; i++) {
Object val = arr[i];
fieldSerializer.write(val, clazz.getComponentType(), sos);
}
}
@Override
public Object read(SimpleInputStream sis, Class> clazz) throws IOException {
int length = sis.readInt();
if (length < 0)
throw new RuntimeException("Invalid array length");
Class> componentType = clazz.getComponentType();
Object[] instance = (Object[]) Array.newInstance(componentType, length);
rememberObject(instance);
for (int i = 0; i < length; i++) {
Object read = fieldSerializer.read(sis, componentType);
instance[i] = read;
}
return instance;
}
}
private class FieldSerializer implements IFieldSerializer {
@SuppressWarnings("unchecked")
public void write(Object object, Class> clazz, SimpleOutputStream sos, boolean noHeader) throws IOException {
if (!noHeader) {
if (!clazz.isPrimitive())
if (!writeHeader(object, clazz, sos))
return;
}
Class extends Object> actualClazz = object.getClass();
if (object.getClass().getEnclosingClass() != null && (object.getClass().getModifiers() & Modifier.STATIC) == 0) {
Object outer = null;
try {
Field outerField = object.getClass().getDeclaredField("this$0");
outerField.setAccessible(true);
outer = outerField.get(object);
fieldSerializer.write(outer, clazz.getEnclosingClass(), sos);
rememberObject(outer);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
if (!clazz.isPrimitive())
rememberObject(object);
if (clazz.isEnum()) {
new SimpleEnumSerializer(clazz).write(sos, (Enum) object);
return;
}
ICompositeSerializer compositeSerializer = (ICompositeSerializer) compositeSerializers.get(actualClazz);
if (compositeSerializer != null) {
compositeSerializer.write(object, actualClazz, sos, fieldSerializer);
return;
}
ISimpleSerializer contentSerializer = (ISimpleSerializer) serializers.get(actualClazz);
if (contentSerializer != null)
contentSerializer.write(sos, object);
else if (actualClazz.getComponentType() != null)
arraySerializer.write(object, actualClazz, sos);
else
pojoSerializer.write(object, actualClazz, sos);
}
@Override
public void write(Object object, Class> clazz, SimpleOutputStream sos) throws IOException {
write(object, clazz, sos, false);
}
public Object read(SimpleInputStream sis, Class> clazz, boolean noHeader) throws IOException {
Class> realClazz = clazz;
if (!noHeader) {
if (!clazz.isPrimitive()) {
// READ HEADER
byte hdr = sis.readByte();
if (hdr == 0)
return null;
else if (hdr == 3) {
int objid = sis.readInt();
Object val = knownObjectList.get(objid);
return val;
} else if (hdr == 1) {
// Nothing, realClazz = clazz
} else if (hdr == 4) {
byte index = sis.readByte();
String className = classes.inverse().get(index);
if (className == null)
throw new ZeSerializerException("Unknown class id: " + index);
realClazz = parseClassName(className);
} else if (hdr == 2) {
String className = sis.readString();
realClazz = parseClassName(className);
} else {
throw new ZeSerializerException("Parsing error: invalid header value: " + hdr
+ " when parsing class " + clazz.getName());
}
}
}
Object outer = null;
if (realClazz.getEnclosingClass() != null && (realClazz.getModifiers() & Modifier.STATIC) == 0) {
outer = read(sis, realClazz.getDeclaringClass());
rememberObject(outer);
}
Object object = readObject(sis, realClazz, outer);
if (!realClazz.isPrimitive()) {
rememberObject(object);
}
return object;
}
@SuppressWarnings("unchecked")
private Object readObject(SimpleInputStream sis, Class> realClazz, Object outer) throws IOException {
if (realClazz.isEnum()) {
return new SimpleEnumSerializer(realClazz).read(sis);
}
ICompositeSerializer compositeSerializer = (ICompositeSerializer) compositeSerializers.get(realClazz);
if (compositeSerializer != null)
return compositeSerializer.read(sis, realClazz, fieldSerializer, ZeSerializer.this::rememberObject);
ISimpleSerializer contentSerializer = (ISimpleSerializer) serializers.get(realClazz);
if (contentSerializer != null)
return contentSerializer.read(sis);
else if (realClazz.getComponentType() != null)
return arraySerializer.read(sis, realClazz);
else
return pojoSerializer.read(sis, realClazz, outer);
}
@Override
public Object read(SimpleInputStream sis, Class> clazz) throws IOException {
Object object = read(sis, clazz, false);
return object;
}
// TODO: check and fix circular references
private boolean writeHeader(Object val, Class> clazz, SimpleOutputStream sos) throws IOException {
if (val == null) {
sos.write((byte) 0);
return false;
}
Integer objId = knownObjects.get(new Wrap(val));
if (objId != null) {
sos.write((byte) 3);
sos.write(objId.intValue());
return false;
}
if (val.getClass() == clazz) {
sos.write((byte) 1);
} else {
String clname = val.getClass().getName();
Byte index = classes.get(clname);
if (index == null) {
sos.write((byte) 2);
sos.write(clname);
// System.err.println("DIFFERING class : " + clazz.getCanonicalName() + " -->> " + val.getClass().getCanonicalName());
} else {
sos.write((byte) 4);
sos.write(index.byteValue());
}
}
return true;
}
}
private static class HashMapSerializer implements ICompositeSerializer> {
@Override
public void write(HashMap, ?> object, Class extends HashMap, ?>> clazz, SimpleOutputStream sos, IFieldSerializer fieldSerializer) throws IOException {
sos.write(object.size());
for (Entry, ?> e : object.entrySet()) {
fieldSerializer.write(e.getKey(), Object.class, sos);
fieldSerializer.write(e.getValue(), Object.class, sos);
}
}
@SuppressWarnings("unchecked")
@Override
public HashMap, ?> read(SimpleInputStream sis, Class extends HashMap, ?>> clazz, IFieldSerializer fieldSerializer, Consumer rememberer) throws IOException {
HashMap hm = new HashMap();
rememberer.accept(hm);
int len = sis.readInt();
for (int i = 0; i < len; i++) {
Object key = fieldSerializer.read(sis, Object.class);
Object value = fieldSerializer.read(sis, Object.class);
hm.put(key, value);
}
return hm;
}
}
private static class CollectionSerializer implements ICompositeSerializer {
@Override
public void write(T val, Class extends T> clazz, SimpleOutputStream sos, IFieldSerializer fieldSerializer) throws IOException {
sos.write(val.size());
// Optimization: same class
long classesNum = (int) Stream.of((List>)val).filter(o -> o != null).map(Object::getClass).distinct().count();
if (classesNum < val.size() - 2) {
sos.write((byte) 1);
List> classes = Stream.of((List>)val)
.filter(o -> o != null)
.map(Object::getClass)
.distinct()
.collect(Collectors.toList());
Map, Integer> map = IntStream.range(0, classes.size()).boxed().collect(Collectors.toMap(classes::get, i -> i));
sos.write(classes.size());
for (Class cl : classes) {
sos.write(cl.getName());
}
for (Object element : val) {
sos.write(map.get(element.getClass()).intValue()); // TODO : optimize by size (byte/short/int !!!)
fieldSerializer.write(element, element.getClass(), sos);
}
} else {
sos.write((byte) 2);
for (Object element : val) {
fieldSerializer.write(element, Object.class, sos);
}
}
}
@SuppressWarnings("unchecked")
@Override
public T read(SimpleInputStream sis, Class extends T> clazz, IFieldSerializer fieldSerializer, Consumer rememberer) throws IOException {
Collection instance = null;
try {
instance = (Collection) instantiateUsingNoArgCtor(clazz);
rememberer.accept(instance);
} catch (Exception e) {
throw new ZeSerializerException(e);
}
int len = sis.readInt();
byte type = sis.readByte();
if (type == 2) {
for (int i = 0; i < len; i++) {
Object value = fieldSerializer.read(sis, Object.class);
instance.add(value);
}
} else if (type == 1) {
int classesCount = sis.readInt();
Class[] classes = new Class[classesCount];
for (int i = 0; i < classesCount; i++) {
classes[i] = parseClassName(sis.readString());
}
for (int i = 0; i < len; i++) {
int classIndex = sis.readInt();
Class> clazzz = classes[classIndex];
Object value = fieldSerializer.read(sis, clazzz);
instance.add(value);
}
} else
throw new ZeSerializerException("Wrong collection encoding type " + type);
return (T) instance;
}
}
private static class Wrap {
private Object object;
public Wrap(Object object) {
this.object = object;
}
@Override
public int hashCode() {
return System.identityHashCode(object) + 5;
}
@Override
public boolean equals(Object that) {
return this.object == ((Wrap) that).object;
}
}
}