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