Skip to content

Commit f4a2918

Browse files
author
Doomkopf
committed
Initial commit
1 parent 8c80060 commit f4a2918

37 files changed

+1392
-0
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/target/
2+
/bin/
3+
/.settings/
4+
.classpath
5+
.project

pom.xml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
2+
<modelVersion>4.0.0</modelVersion>
3+
4+
<groupId>com.hypercode</groupId>
5+
<artifactId>binary-serializer</artifactId>
6+
<version>0.1.0-SNAPSHOT</version>
7+
8+
<dependencies>
9+
<dependency>
10+
<groupId>junit</groupId>
11+
<artifactId>junit</artifactId>
12+
<version>4.12</version>
13+
<scope>test</scope>
14+
</dependency>
15+
</dependencies>
16+
<build>
17+
<plugins>
18+
<plugin>
19+
<groupId>org.apache.maven.plugins</groupId>
20+
<artifactId>maven-compiler-plugin</artifactId>
21+
<version>3.6.0</version>
22+
<configuration>
23+
<source>1.5</source>
24+
<target>1.5</target>
25+
</configuration>
26+
</plugin>
27+
</plugins>
28+
</build>
29+
30+
</project>
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
package com.hypercode.binaryserializer;
2+
3+
import java.io.Externalizable;
4+
import java.lang.reflect.Constructor;
5+
import java.lang.reflect.Field;
6+
import java.lang.reflect.Modifier;
7+
import java.nio.BufferOverflowException;
8+
import java.nio.ByteBuffer;
9+
import java.util.ArrayList;
10+
import java.util.Collection;
11+
import java.util.LinkedList;
12+
import java.util.List;
13+
import java.util.Map;
14+
import java.util.concurrent.ConcurrentHashMap;
15+
16+
import com.hypercode.binaryserializer.typeserializer.ArrayTypeSerializer;
17+
import com.hypercode.binaryserializer.typeserializer.CollectionTypeSerializer;
18+
import com.hypercode.binaryserializer.typeserializer.ComplexTypeSerializer;
19+
import com.hypercode.binaryserializer.typeserializer.ComplexTypeSerializer.InternalField;
20+
import com.hypercode.binaryserializer.typeserializer.EnumTypeSerializer;
21+
import com.hypercode.binaryserializer.typeserializer.MapTypeSerializer;
22+
import com.hypercode.binaryserializer.typeserializer.SerializableTypeSerializer;
23+
import com.hypercode.binaryserializer.typeserializer.UnknownTypeSerializer;
24+
import com.hypercode.binaryserializer.typeserializer.simple.SimpleTypes;
25+
26+
public class BinarySerializer {
27+
28+
private static final int RESIZE_BYTES = 1024;
29+
30+
private final Map<Class<?>, TypeSerializer> classToTypeMap = new ConcurrentHashMap<Class<?>, TypeSerializer>();
31+
private final ThreadLocal<ByteBuffer> threadLocalByteBuffer = new ThreadLocal<ByteBuffer>();
32+
private final TypeFactoryProvider typeFactoryProvider;
33+
private final UnknownTypeSerializer unknownTypeSerializer = new UnknownTypeSerializer(this);
34+
private final CollectionTypeSerializer<?> collectionTypeSerializer;
35+
private final MapTypeSerializer mapTypeSerializer;
36+
37+
private int bufferSize = RESIZE_BYTES;
38+
39+
@SuppressWarnings("rawtypes")
40+
public BinarySerializer(Collection<Mapping<Class<?>, TypeFactory>> typeFactoryMappings) {
41+
typeFactoryProvider = new TypeFactoryProvider(typeFactoryMappings);
42+
collectionTypeSerializer = new CollectionTypeSerializer(unknownTypeSerializer, typeFactoryProvider);
43+
mapTypeSerializer = new MapTypeSerializer(unknownTypeSerializer, typeFactoryProvider);
44+
}
45+
46+
@SuppressWarnings({ "unchecked", "rawtypes" })
47+
public BinarySerializer() {
48+
this(new ArrayList(0));
49+
}
50+
51+
private ByteBuffer getByteBuffer() {
52+
53+
ByteBuffer byteBuffer = threadLocalByteBuffer.get();
54+
if (byteBuffer == null || byteBuffer.capacity() < bufferSize) {
55+
byteBuffer = ByteBuffer.allocate(bufferSize);
56+
threadLocalByteBuffer.set(byteBuffer);
57+
} else {
58+
byteBuffer.clear();
59+
}
60+
61+
return byteBuffer;
62+
}
63+
64+
public TypeSerializer getOrCreateType(Class<?> clazz) {
65+
66+
TypeSerializer typeSerializer = SimpleTypes.findType(clazz);
67+
if (typeSerializer == null) {
68+
if (Externalizable.class.isAssignableFrom(clazz)) {
69+
return SerializableTypeSerializer.INSTANCE;
70+
}
71+
72+
if (Collection.class.isAssignableFrom(clazz)) {
73+
return collectionTypeSerializer;
74+
}
75+
76+
if (Map.class.isAssignableFrom(clazz)) {
77+
return mapTypeSerializer;
78+
}
79+
80+
int mod = clazz.getModifiers();
81+
if (!clazz.isArray() && (Modifier.isInterface(mod) || Modifier.isAbstract(mod) || clazz == Object.class)) {
82+
return unknownTypeSerializer;
83+
}
84+
85+
typeSerializer = classToTypeMap.get(clazz);
86+
if (typeSerializer == null) {
87+
typeSerializer = createType(clazz);
88+
TypeSerializer existing = classToTypeMap.putIfAbsent(clazz, typeSerializer);
89+
if (existing != null) {
90+
typeSerializer = existing;
91+
}
92+
}
93+
}
94+
95+
return typeSerializer;
96+
}
97+
98+
private TypeSerializer createType(Class<?> clazz) {
99+
100+
if (clazz.isArray()) {
101+
clazz = clazz.getComponentType();
102+
return new ArrayTypeSerializer(getOrCreateType(clazz), clazz);
103+
}
104+
105+
if (clazz.isEnum()) {
106+
return new EnumTypeSerializer(clazz);
107+
}
108+
109+
return createComplexType(clazz);
110+
}
111+
112+
private TypeSerializer createComplexType(Class<?> clazz) {
113+
114+
List<InternalField> fields = new LinkedList<InternalField>();
115+
List<Field> recFields = new LinkedList<Field>();
116+
for (java.lang.reflect.Field field : clazz.getDeclaredFields()) {
117+
int mod = field.getModifiers();
118+
if (Modifier.isTransient(mod) || Modifier.isStatic(mod)) {
119+
continue;
120+
}
121+
if (Modifier.isFinal(mod)) {
122+
return SerializableTypeSerializer.INSTANCE;
123+
}
124+
if (!field.isAccessible()) {
125+
field.setAccessible(true);
126+
}
127+
if (field.getType() == clazz) {
128+
recFields.add(field);
129+
continue;
130+
}
131+
132+
fields.add(new InternalField(field, getOrCreateType(field.getType())));
133+
}
134+
135+
Constructor<?> localConstructor = null;
136+
try {
137+
localConstructor = clazz.getDeclaredConstructor();
138+
} catch (NoSuchMethodException e) {
139+
// expected exception used for control flow
140+
} catch (SecurityException e) {
141+
// expected exception used for control flow
142+
}
143+
144+
TypeFactory typeFactory;
145+
if (localConstructor == null) {
146+
typeFactory = typeFactoryProvider.getTypeFactory(clazz);
147+
} else {
148+
if (!localConstructor.isAccessible()) {
149+
localConstructor.setAccessible(true);
150+
}
151+
final Constructor<?> constructor = localConstructor;
152+
typeFactory = new TypeFactory() {
153+
public Object create() throws Exception {
154+
return constructor.newInstance();
155+
}
156+
};
157+
}
158+
159+
ComplexTypeSerializer type = new ComplexTypeSerializer(typeFactory, fields);
160+
for (java.lang.reflect.Field field : recFields) {
161+
fields.add(new InternalField(field, type));
162+
}
163+
164+
return type;
165+
}
166+
167+
public byte[] serialize(Object obj) throws Exception {
168+
169+
ByteBuffer byteBuffer;
170+
TypeSerializer typeSerializer = getOrCreateType(obj.getClass());
171+
while (true) {
172+
byteBuffer = getByteBuffer();
173+
try {
174+
typeSerializer.writeObjectToBuffer(obj, byteBuffer);
175+
break;
176+
} catch (BufferOverflowException e) {
177+
bufferSize += RESIZE_BYTES;
178+
}
179+
}
180+
181+
byte[] bytes = new byte[byteBuffer.position()];
182+
byteBuffer.position(0);
183+
byteBuffer.get(bytes);
184+
return bytes;
185+
}
186+
187+
@SuppressWarnings("unchecked")
188+
public <T> T deserialize(byte[] bytes, Class<T> clazz) throws Exception {
189+
return (T) getOrCreateType(clazz).readObjectFromBuffer(ByteBuffer.wrap(bytes));
190+
}
191+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.hypercode.binaryserializer;
2+
3+
public interface Constants {
4+
5+
byte BYTE_TRUE = 1;
6+
byte BYTE_FALSE = 0;
7+
8+
byte BYTE_NULL = 0;
9+
byte BYTE_NOT_NULL = 1;
10+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.hypercode.binaryserializer;
2+
3+
public class Mapping<K, V> {
4+
5+
public final K key;
6+
public final V value;
7+
8+
public Mapping(K key, V value) {
9+
this.key = key;
10+
this.value = value;
11+
}
12+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.hypercode.binaryserializer;
2+
3+
public interface TypeFactory {
4+
Object create() throws Exception;
5+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.hypercode.binaryserializer;
2+
3+
import java.util.Collection;
4+
import java.util.HashMap;
5+
import java.util.Map;
6+
7+
public class TypeFactoryProvider {
8+
9+
private final Map<Class<?>, TypeFactory> map = new HashMap<Class<?>, TypeFactory>();
10+
11+
public TypeFactoryProvider(Collection<Mapping<Class<?>, TypeFactory>> typeFactoryMappings) {
12+
for (Mapping<Class<?>, TypeFactory> mapping : typeFactoryMappings) {
13+
map.put(mapping.key, mapping.value);
14+
}
15+
}
16+
17+
public TypeFactory getTypeFactory(Class<?> clazz) {
18+
return map.get(clazz);
19+
}
20+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.hypercode.binaryserializer;
2+
3+
import java.nio.ByteBuffer;
4+
5+
public interface TypeSerializer {
6+
void writeObjectToBuffer(Object obj, ByteBuffer buffer) throws Exception;
7+
Object readObjectFromBuffer(ByteBuffer buffer) throws Exception;
8+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package com.hypercode.binaryserializer.typeserializer;
2+
3+
import java.lang.reflect.Array;
4+
import java.nio.ByteBuffer;
5+
6+
import com.hypercode.binaryserializer.TypeSerializer;
7+
8+
public class ArrayTypeSerializer extends NullRefAwareTypeSerializer {
9+
10+
private final TypeSerializer typeSerializer;
11+
private final Class<?> clazz;
12+
13+
public ArrayTypeSerializer(TypeSerializer typeSerializer, Class<?> clazz) {
14+
this.typeSerializer = typeSerializer;
15+
this.clazz = clazz;
16+
}
17+
18+
@Override
19+
public void writeNotNullObjectToBuffer(Object obj, ByteBuffer buffer) throws Exception {
20+
21+
int length = Array.getLength(obj);
22+
buffer.putInt(length);
23+
for (int i = 0; i < length; i++) {
24+
Object elem = Array.get(obj, i);
25+
typeSerializer.writeObjectToBuffer(elem, buffer);
26+
}
27+
}
28+
29+
@Override
30+
public Object readNotNullObjectFromBuffer(ByteBuffer buffer) throws Exception {
31+
32+
int length = buffer.getInt();
33+
Object array = Array.newInstance(clazz, length);
34+
for (int i = 0; i < length; i++) {
35+
Array.set(array, i, typeSerializer.readObjectFromBuffer(buffer));
36+
}
37+
38+
return array;
39+
}
40+
}

0 commit comments

Comments
 (0)