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
+ }
0 commit comments