View Javadoc
1   package org.djutils.serialization;
2   
3   import java.nio.charset.Charset;
4   import java.util.ArrayList;
5   import java.util.HashMap;
6   import java.util.List;
7   import java.util.Map;
8   
9   import org.djunits.unit.Unit;
10  import org.djunits.value.vdouble.matrix.base.DoubleMatrix;
11  import org.djunits.value.vdouble.scalar.base.DoubleScalar;
12  import org.djunits.value.vdouble.vector.base.DoubleVector;
13  import org.djunits.value.vfloat.matrix.base.FloatMatrix;
14  import org.djunits.value.vfloat.scalar.base.FloatScalar;
15  import org.djunits.value.vfloat.vector.base.FloatVector;
16  import org.djutils.exceptions.Throw;
17  import org.djutils.serialization.serializers.BasicPrimitiveArrayOrMatrixSerializer;
18  import org.djutils.serialization.serializers.DoubleMatrixSerializer;
19  import org.djutils.serialization.serializers.DoubleScalarSerializer;
20  import org.djutils.serialization.serializers.DoubleVectorArraySerializer;
21  import org.djutils.serialization.serializers.DoubleVectorSerializer;
22  import org.djutils.serialization.serializers.FixedSizeObjectSerializer;
23  import org.djutils.serialization.serializers.FloatMatrixSerializer;
24  import org.djutils.serialization.serializers.FloatScalarSerializer;
25  import org.djutils.serialization.serializers.FloatVectorSerializer;
26  import org.djutils.serialization.serializers.ObjectArraySerializer;
27  import org.djutils.serialization.serializers.ObjectMatrixSerializer;
28  import org.djutils.serialization.serializers.ObjectSerializer;
29  import org.djutils.serialization.serializers.Pointer;
30  import org.djutils.serialization.serializers.Serializer;
31  
32  /**
33   * Message conversions. These take into account the endianness for coding the different values. Java is by default big-endian.
34   * <p>
35   * Copyright (c) 2016-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
36   * BSD-style license. See <a href="https://sim0mq.org/docs/current/license.html">OpenTrafficSim License</a>.
37   * </p>
38   * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
39   * @author <a href="https://www.tudelft.nl/staff/p.knoppers/">Peter Knoppers</a>
40   */
41  public final class TypedMessage
42  {
43      /**
44       * Do not instantiate this utility class.
45       */
46      private TypedMessage()
47      {
48          // Utility class; do not instantiate.
49      }
50  
51      /** The easy converters keyed by Class. */
52      private static final Map<Class<?>, Serializer<?>> ENCODERS = new HashMap<>();
53  
54      /** All the converters that decode into primitive data when possible, keyed by prefix. */
55      static final Map<Byte, Serializer<?>> PRIMITIVE_DATA_DECODERS = new HashMap<>();
56  
57      /** All the converters that decode into arrays and matrices of Objects, keyed by prefix. */
58      private static final Map<Byte, Serializer<?>> OBJECT_DECODERS = new HashMap<>();
59  
60      /** Converter for Byte. */
61      private static final Serializer<Byte> CONVERT_BYTE = new FixedSizeObjectSerializer<Byte>(FieldTypes.BYTE_8, 1, "Byte_8")
62      {
63          @Override
64          public void serialize(final Byte object, final byte[] buffer, final Pointer pointer, final EndianUtil endianUtil)
65          {
66              buffer[pointer.getAndIncrement(1)] = object;
67          }
68  
69          @Override
70          public Byte deSerialize(final byte[] buffer, final Pointer pointer, final EndianUtil endianUtil)
71          {
72              return buffer[pointer.getAndIncrement(1)];
73          }
74      };
75  
76      /** Converter for Short. */
77      private static final Serializer<Short> CONVERT_SHORT =
78              new FixedSizeObjectSerializer<Short>(FieldTypes.SHORT_16, 2, "Short_16")
79              {
80                  @Override
81                  public void serialize(final Short object, final byte[] buffer, final Pointer pointer,
82                          final EndianUtil endianUtil)
83                  {
84                      endianUtil.encodeShort(object, buffer, pointer.getAndIncrement(2));
85                  }
86  
87                  @Override
88                  public Short deSerialize(final byte[] buffer, final Pointer pointer, final EndianUtil endianUtil)
89                  {
90                      return endianUtil.decodeShort(buffer, pointer.getAndIncrement(2));
91                  }
92              };
93  
94      /** Converter for Integer. */
95      private static final Serializer<Integer> CONVERT_INTEGER =
96              new FixedSizeObjectSerializer<Integer>(FieldTypes.INT_32, 4, "Integer_32")
97              {
98                  @Override
99                  public void serialize(final Integer object, final byte[] buffer, final Pointer pointer,
100                         final EndianUtil endianUtil)
101                 {
102                     endianUtil.encodeInt(object, buffer, pointer.getAndIncrement(4));
103                 }
104 
105                 @Override
106                 public Integer deSerialize(final byte[] buffer, final Pointer pointer, final EndianUtil endianUtil)
107                 {
108                     return endianUtil.decodeInt(buffer, pointer.getAndIncrement(4));
109                 }
110             };
111 
112     /** Converter for Integer. */
113     private static final Serializer<Long> CONVERT_LONG = new FixedSizeObjectSerializer<Long>(FieldTypes.LONG_64, 8, "Long_64")
114     {
115         @Override
116         public void serialize(final Long object, final byte[] buffer, final Pointer pointer, final EndianUtil endianUtil)
117         {
118             endianUtil.encodeLong(object, buffer, pointer.getAndIncrement(8));
119         }
120 
121         @Override
122         public Long deSerialize(final byte[] buffer, final Pointer pointer, final EndianUtil endianUtil)
123         {
124             return endianUtil.decodeLong(buffer, pointer.getAndIncrement(8));
125         }
126     };
127 
128     /** Converter for Float. */
129     private static final Serializer<Float> CONVERT_FLOAT =
130             new FixedSizeObjectSerializer<Float>(FieldTypes.FLOAT_32, 4, "Float_32")
131             {
132                 @Override
133                 public void serialize(final Float object, final byte[] buffer, final Pointer pointer,
134                         final EndianUtil endianUtil)
135                 {
136                     endianUtil.encodeFloat(object, buffer, pointer.getAndIncrement(4));
137                 }
138 
139                 @Override
140                 public Float deSerialize(final byte[] buffer, final Pointer pointer, final EndianUtil endianUtil)
141                 {
142                     return endianUtil.decodeFloat(buffer, pointer.getAndIncrement(4));
143                 }
144             };
145 
146     /** Converter for Double. */
147     private static final Serializer<Double> CONVERT_DOUBLE =
148             new FixedSizeObjectSerializer<Double>(FieldTypes.DOUBLE_64, 8, "Double_64")
149             {
150                 @Override
151                 public void serialize(final Double object, final byte[] buffer, final Pointer pointer,
152                         final EndianUtil endianUtil)
153                 {
154                     endianUtil.encodeDouble(object, buffer, pointer.getAndIncrement(8));
155                 }
156 
157                 @Override
158                 public Double deSerialize(final byte[] buffer, final Pointer pointer, final EndianUtil endianUtil)
159                 {
160                     return endianUtil.decodeDouble(buffer, pointer.getAndIncrement(8));
161                 }
162             };
163 
164     /** Converter for Boolean. */
165     private static final Serializer<Boolean> CONVERT_BOOLEAN =
166             new FixedSizeObjectSerializer<Boolean>(FieldTypes.BOOLEAN_8, 1, "Boolean_8")
167             {
168                 @Override
169                 public void serialize(final Boolean object, final byte[] buffer, final Pointer pointer,
170                         final EndianUtil endianUtil)
171                 {
172                     buffer[pointer.getAndIncrement(1)] = (byte) (object ? 1 : 0);
173                 }
174 
175                 @Override
176                 public Boolean deSerialize(final byte[] buffer, final Pointer pointer, final EndianUtil endianUtil)
177                 {
178                     return buffer[pointer.getAndIncrement(1)] != 0;
179                 }
180             };
181 
182     /** Converter for Character. */
183     private static final Serializer<Character> CONVERT_CHARACTER16 =
184             new FixedSizeObjectSerializer<Character>(FieldTypes.CHAR_16, 2, "Char_16")
185             {
186                 @Override
187                 public void serialize(final Character object, final byte[] buffer, final Pointer pointer,
188                         final EndianUtil endianUtil)
189                 {
190                     endianUtil.encodeChar(object, buffer, pointer.getAndIncrement(size(object)));
191                 }
192 
193                 @Override
194                 public Character deSerialize(final byte[] buffer, final Pointer pointer, final EndianUtil endianUtil)
195                 {
196                     return endianUtil.decodeChar(buffer, pointer.getAndIncrement(2));
197                 }
198             };
199 
200     /** Converter for Character. */
201     private static final Serializer<Character> CONVERT_CHARACTER8 =
202             new FixedSizeObjectSerializer<Character>(FieldTypes.CHAR_8, 1, "Char_8")
203             {
204                 @Override
205                 public void serialize(final Character object, final byte[] buffer, final Pointer pointer,
206                         final EndianUtil endianUtil)
207                 {
208                     buffer[pointer.getAndIncrement(size(object))] = (byte) (object & 0xFF);
209                 }
210 
211                 @Override
212                 public Character deSerialize(final byte[] buffer, final Pointer pointer, final EndianUtil endianUtil)
213                 {
214                     return Character.valueOf((char) buffer[pointer.getAndIncrement(1)]);
215                 }
216             };
217 
218     /** Converter for String. */
219     private static final Serializer<String> CONVERT_STRING16 = new ObjectSerializer<String>(FieldTypes.STRING_16, "String_16")
220     {
221         @Override
222         public int size(final String object)
223         {
224             return 4 + object.getBytes(UTF16).length;
225         }
226 
227         @Override
228         public void serialize(final String string, final byte[] buffer, final Pointer pointer, final EndianUtil endianUtil)
229         {
230             // System.out.println("Encoding string \"" + string + "\"");
231             char[] chars = new char[string.length()];
232             string.getChars(0, chars.length, chars, 0);
233             endianUtil.encodeInt(chars.length, buffer, pointer.getAndIncrement(4));
234             // int originalPos = pointer.get();
235             for (char c : chars)
236             {
237                 endianUtil.encodeChar(c, buffer, pointer.getAndIncrement(2));
238             }
239             // System.out.println("encoded string starts at " + originalPos);
240             // System.out.print(HexDumper.hexDumper(buffer));
241         }
242 
243         @Override
244         public String deSerialize(final byte[] buffer, final Pointer pointer, final EndianUtil endianUtil)
245         {
246             // System.out.println("Input bytes");
247             // System.out.print(HexDumper.hexDumper(buffer));
248             String s = endianUtil.decodeUTF16String(buffer, pointer.get());
249             pointer.getAndIncrement(4 + s.length() * 2);
250             return s;
251         }
252     };
253 
254     /** Converter for String. */
255     private static final Serializer<String> CONVERT_STRING8 = new ObjectSerializer<String>(FieldTypes.STRING_8, "String_8")
256     {
257         @Override
258         public int size(final String string)
259         {
260             return 4 + string.getBytes(UTF8).length;
261         }
262 
263         @Override
264         public void serialize(final String string, final byte[] buffer, final Pointer pointer, final EndianUtil endianUtil)
265         {
266             byte[] s = string.getBytes(UTF8);
267             endianUtil.encodeInt(s.length, buffer, pointer.getAndIncrement(4));
268             for (byte b : s)
269             {
270                 buffer[pointer.getAndIncrement(1)] = b;
271             }
272         }
273 
274         @Override
275         public String deSerialize(final byte[] buffer, final Pointer pointer, final EndianUtil endianUtil)
276                 throws SerializationException
277         {
278             int bytesUsed = endianUtil.decodeInt(buffer, pointer.get());
279             String s = endianUtil.decodeUTF8String(buffer, pointer.get());
280             pointer.getAndIncrement(4 + bytesUsed);
281             return s;
282         }
283     };
284 
285     /** Converter for byte array. */
286     private static final Serializer<byte[]> CONVERT_BT_ARRAY =
287             new BasicPrimitiveArrayOrMatrixSerializer<byte[]>(FieldTypes.BYTE_8_ARRAY, 1, "byte_8_array", 1)
288             {
289                 @Override
290                 public int size(final byte[] array)
291                 {
292                     return 4 + getElementSize() * array.length;
293                 }
294 
295                 @Override
296                 public void serialize(final byte[] array, final byte[] buffer, final Pointer pointer,
297                         final EndianUtil endianUtil) throws SerializationException
298                 {
299                     endianUtil.encodeInt(array.length, buffer, pointer.getAndIncrement(4));
300                     for (int i = 0; i < array.length; i++)
301                     {
302                         buffer[pointer.getAndIncrement(getElementSize())] = array[i];
303                     }
304                 }
305 
306                 @Override
307                 public byte[] deSerialize(final byte[] buffer, final Pointer pointer, final EndianUtil endianUtil)
308                         throws SerializationException
309                 {
310                     int size = endianUtil.decodeInt(buffer, pointer.getAndIncrement(4));
311                     byte[] result = new byte[size];
312                     for (int i = 0; i < size; i++)
313                     {
314                         result[i] = buffer[pointer.getAndIncrement(getElementSize())];
315                     }
316                     return result;
317                 }
318             };
319 
320     /** Converter for Byte array. */
321     private static final Serializer<Byte[]> CONVERT_BYTE_ARRAY =
322             new ObjectArraySerializer<Byte>(FieldTypes.BYTE_8_ARRAY, 1, Byte.valueOf((byte) 0), "Byte_8_array")
323             {
324                 @Override
325                 public void serializeElement(final Byte object, final byte[] buffer, final int offset,
326                         final EndianUtil endianUtil)
327                 {
328                     buffer[offset] = object;
329                 }
330 
331                 @Override
332                 public Byte deSerializeElement(final byte[] buffer, final int offset, final EndianUtil endianUtil)
333                 {
334                     return buffer[offset];
335                 }
336             };
337 
338     /** Converter for short array. */
339     private static final Serializer<short[]> CONVERT_SHRT_ARRAY =
340             new BasicPrimitiveArrayOrMatrixSerializer<short[]>(FieldTypes.SHORT_16_ARRAY, 2, "short_16_array", 1)
341             {
342                 @Override
343                 public int size(final short[] array)
344                 {
345                     return 4 + getElementSize() * array.length;
346                 }
347 
348                 @Override
349                 public void serialize(final short[] array, final byte[] buffer, final Pointer pointer,
350                         final EndianUtil endianUtil) throws SerializationException
351                 {
352                     endianUtil.encodeInt(array.length, buffer, pointer.getAndIncrement(4));
353                     for (int i = 0; i < array.length; i++)
354                     {
355                         endianUtil.encodeShort(array[i], buffer, pointer.getAndIncrement(getElementSize()));
356                     }
357                 }
358 
359                 @Override
360                 public short[] deSerialize(final byte[] buffer, final Pointer pointer, final EndianUtil endianUtil)
361                         throws SerializationException
362                 {
363                     int size = endianUtil.decodeInt(buffer, pointer.getAndIncrement(4));
364                     short[] result = new short[size];
365                     for (int i = 0; i < size; i++)
366                     {
367                         result[i] = endianUtil.decodeShort(buffer, pointer.getAndIncrement(getElementSize()));
368                     }
369                     return result;
370                 }
371             };
372 
373     /** Converter for Short array. */
374     private static final Serializer<Short[]> CONVERT_SHORT_ARRAY =
375             new ObjectArraySerializer<Short>(FieldTypes.SHORT_16_ARRAY, 2, Short.valueOf((short) 0), "Short_16_array")
376             {
377                 @Override
378                 public void serializeElement(final Short object, final byte[] buffer, final int offset,
379                         final EndianUtil endianUtil)
380                 {
381                     endianUtil.encodeShort(object, buffer, offset);
382                 }
383 
384                 @Override
385                 public Short deSerializeElement(final byte[] buffer, final int offset, final EndianUtil endianUtil)
386                 {
387                     return endianUtil.decodeShort(buffer, offset);
388                 }
389             };
390 
391     /** Converter for int array. */
392     private static final Serializer<int[]> CONVERT_INT_ARRAY =
393             new BasicPrimitiveArrayOrMatrixSerializer<int[]>(FieldTypes.INT_32_ARRAY, 4, "int_32_array", 1)
394             {
395                 @Override
396                 public int size(final int[] array)
397                 {
398                     return 4 + getElementSize() * array.length;
399                 }
400 
401                 @Override
402                 public void serialize(final int[] array, final byte[] buffer, final Pointer pointer,
403                         final EndianUtil endianUtil) throws SerializationException
404                 {
405                     endianUtil.encodeInt(array.length, buffer, pointer.getAndIncrement(4));
406                     for (int i = 0; i < array.length; i++)
407                     {
408                         endianUtil.encodeInt(array[i], buffer, pointer.getAndIncrement(getElementSize()));
409                     }
410                 }
411 
412                 @Override
413                 public int[] deSerialize(final byte[] buffer, final Pointer pointer, final EndianUtil endianUtil)
414                         throws SerializationException
415                 {
416                     int size = endianUtil.decodeInt(buffer, pointer.getAndIncrement(4));
417                     int[] result = new int[size];
418                     for (int i = 0; i < size; i++)
419                     {
420                         result[i] = endianUtil.decodeInt(buffer, pointer.getAndIncrement(getElementSize()));
421                     }
422                     return result;
423                 }
424             };
425 
426     /** Converter for Integer array. */
427     private static final Serializer<Integer[]> CONVERT_INTEGER_ARRAY =
428             new ObjectArraySerializer<Integer>(FieldTypes.INT_32_ARRAY, 4, Integer.valueOf(0), "Integer_32_array")
429             {
430                 @Override
431                 public void serializeElement(final Integer object, final byte[] buffer, final int offset,
432                         final EndianUtil endianUtil)
433                 {
434                     endianUtil.encodeInt(object, buffer, offset);
435                 }
436 
437                 @Override
438                 public Integer deSerializeElement(final byte[] buffer, final int offset, final EndianUtil endianUtil)
439                 {
440                     return endianUtil.decodeInt(buffer, offset);
441                 }
442             };
443 
444     /** Converter for long array. */
445     private static final Serializer<long[]> CONVERT_LNG_ARRAY =
446             new BasicPrimitiveArrayOrMatrixSerializer<long[]>(FieldTypes.LONG_64_ARRAY, 8, "long_64_array", 1)
447             {
448                 @Override
449                 public int size(final long[] array)
450                 {
451                     return 4 + getElementSize() * array.length;
452                 }
453 
454                 @Override
455                 public void serialize(final long[] array, final byte[] buffer, final Pointer pointer,
456                         final EndianUtil endianUtil) throws SerializationException
457                 {
458                     endianUtil.encodeInt(array.length, buffer, pointer.getAndIncrement(4));
459                     for (int i = 0; i < array.length; i++)
460                     {
461                         endianUtil.encodeLong(array[i], buffer, pointer.getAndIncrement(getElementSize()));
462                     }
463                 }
464 
465                 @Override
466                 public long[] deSerialize(final byte[] buffer, final Pointer pointer, final EndianUtil endianUtil)
467                         throws SerializationException
468                 {
469                     int size = endianUtil.decodeInt(buffer, pointer.getAndIncrement(4));
470                     long[] result = new long[size];
471                     for (int i = 0; i < size; i++)
472                     {
473                         result[i] = endianUtil.decodeLong(buffer, pointer.getAndIncrement(getElementSize()));
474                     }
475                     return result;
476                 }
477             };
478 
479     /** Converter for Long array. */
480     private static final Serializer<Long[]> CONVERT_LONG_ARRAY =
481             new ObjectArraySerializer<Long>(FieldTypes.LONG_64_ARRAY, 8, Long.valueOf(0), "Long_64_array")
482             {
483                 @Override
484                 public void serializeElement(final Long object, final byte[] buffer, final int offset,
485                         final EndianUtil endianUtil)
486                 {
487                     endianUtil.encodeLong(object, buffer, offset);
488                 }
489 
490                 @Override
491                 public Long deSerializeElement(final byte[] buffer, final int offset, final EndianUtil endianUtil)
492                 {
493                     return endianUtil.decodeLong(buffer, offset);
494                 }
495             };
496 
497     /** Converter for float array. */
498     private static final Serializer<float[]> CONVERT_FLT_ARRAY =
499             new BasicPrimitiveArrayOrMatrixSerializer<float[]>(FieldTypes.FLOAT_32_ARRAY, 4, "float_32_array", 1)
500             {
501                 @Override
502                 public int size(final float[] array)
503                 {
504                     return 4 + getElementSize() * array.length;
505                 }
506 
507                 @Override
508                 public void serialize(final float[] array, final byte[] buffer, final Pointer pointer,
509                         final EndianUtil endianUtil) throws SerializationException
510                 {
511                     endianUtil.encodeInt(array.length, buffer, pointer.getAndIncrement(4));
512                     for (int i = 0; i < array.length; i++)
513                     {
514                         endianUtil.encodeFloat(array[i], buffer, pointer.getAndIncrement(getElementSize()));
515                     }
516                 }
517 
518                 @Override
519                 public float[] deSerialize(final byte[] buffer, final Pointer pointer, final EndianUtil endianUtil)
520                         throws SerializationException
521                 {
522                     int size = endianUtil.decodeInt(buffer, pointer.getAndIncrement(4));
523                     float[] result = new float[size];
524                     for (int i = 0; i < size; i++)
525                     {
526                         result[i] = endianUtil.decodeFloat(buffer, pointer.getAndIncrement(getElementSize()));
527                     }
528                     return result;
529                 }
530             };
531 
532     /** Converter for Float array. */
533     private static final Serializer<Float[]> CONVERT_FLOAT_ARRAY =
534             new ObjectArraySerializer<Float>(FieldTypes.FLOAT_32_ARRAY, 4, Float.valueOf(0), "Float_32_array")
535             {
536                 @Override
537                 public void serializeElement(final Float object, final byte[] buffer, final int offset,
538                         final EndianUtil endianUtil)
539                 {
540                     endianUtil.encodeFloat(object, buffer, offset);
541                 }
542 
543                 @Override
544                 public Float deSerializeElement(final byte[] buffer, final int offset, final EndianUtil endianUtil)
545                 {
546                     return endianUtil.decodeFloat(buffer, offset);
547                 }
548             };
549 
550     /** Converter for double array. */
551     private static final Serializer<double[]> CONVERT_DBL_ARRAY =
552             new BasicPrimitiveArrayOrMatrixSerializer<double[]>(FieldTypes.DOUBLE_64_ARRAY, 8, "double_64_array", 1)
553             {
554                 @Override
555                 public int size(final double[] array)
556                 {
557                     return 4 + getElementSize() * array.length;
558                 }
559 
560                 @Override
561                 public void serialize(final double[] array, final byte[] buffer, final Pointer pointer,
562                         final EndianUtil endianUtil) throws SerializationException
563                 {
564                     endianUtil.encodeInt(array.length, buffer, pointer.getAndIncrement(4));
565                     for (int i = 0; i < array.length; i++)
566                     {
567                         endianUtil.encodeDouble(array[i], buffer, pointer.getAndIncrement(getElementSize()));
568                     }
569                 }
570 
571                 @Override
572                 public double[] deSerialize(final byte[] buffer, final Pointer pointer, final EndianUtil endianUtil)
573                         throws SerializationException
574                 {
575                     int size = endianUtil.decodeInt(buffer, pointer.getAndIncrement(4));
576                     double[] result = new double[size];
577                     for (int i = 0; i < size; i++)
578                     {
579                         result[i] = endianUtil.decodeDouble(buffer, pointer.getAndIncrement(getElementSize()));
580                     }
581                     return result;
582                 }
583             };
584 
585     /** Converter for Double array. */
586     private static final Serializer<Double[]> CONVERT_DOUBLE_ARRAY =
587             new ObjectArraySerializer<Double>(FieldTypes.DOUBLE_64_ARRAY, 8, Double.valueOf(0), "Double_64_array")
588             {
589                 @Override
590                 public void serializeElement(final Double object, final byte[] buffer, final int offset,
591                         final EndianUtil endianUtil)
592                 {
593                     endianUtil.encodeDouble(object, buffer, offset);
594                 }
595 
596                 @Override
597                 public Double deSerializeElement(final byte[] buffer, final int offset, final EndianUtil endianUtil)
598                 {
599                     return endianUtil.decodeDouble(buffer, offset);
600                 }
601             };
602 
603     /** Converter for boolean array. */
604     private static final Serializer<boolean[]> CONVERT_BOOL_ARRAY =
605             new BasicPrimitiveArrayOrMatrixSerializer<boolean[]>(FieldTypes.BOOLEAN_8_ARRAY, 1, "bool_8_array", 1)
606             {
607                 @Override
608                 public int size(final boolean[] array)
609                 {
610                     return 4 + getElementSize() * array.length;
611                 }
612 
613                 @Override
614                 public void serialize(final boolean[] array, final byte[] buffer, final Pointer pointer,
615                         final EndianUtil endianUtil) throws SerializationException
616                 {
617                     endianUtil.encodeInt(array.length, buffer, pointer.getAndIncrement(4));
618                     for (int i = 0; i < array.length; i++)
619                     {
620                         buffer[pointer.getAndIncrement(getElementSize())] = (byte) (array[i] ? 1 : 0);
621                     }
622                 }
623 
624                 @Override
625                 public boolean[] deSerialize(final byte[] buffer, final Pointer pointer, final EndianUtil endianUtil)
626                         throws SerializationException
627                 {
628                     int size = endianUtil.decodeInt(buffer, pointer.getAndIncrement(4));
629                     boolean[] result = new boolean[size];
630                     for (int i = 0; i < size; i++)
631                     {
632                         result[i] = buffer[pointer.getAndIncrement(getElementSize())] != 0;
633                     }
634                     return result;
635                 }
636             };
637 
638     /** Converter for Boolean array. */
639     private static final Serializer<Boolean[]> CONVERT_BOOLEAN_ARRAY =
640             new ObjectArraySerializer<Boolean>(FieldTypes.BOOLEAN_8_ARRAY, 1, Boolean.FALSE, "Boolean_8_array")
641             {
642                 @Override
643                 public void serializeElement(final Boolean object, final byte[] buffer, final int offset,
644                         final EndianUtil endianUtil)
645                 {
646                     buffer[offset] = (byte) (object ? 1 : 0);
647                 }
648 
649                 @Override
650                 public Boolean deSerializeElement(final byte[] buffer, final int offset, final EndianUtil endianUtil)
651                 {
652                     return buffer[offset] != 0;
653                 }
654             };
655 
656     /** Converter for byte matrix. */
657     private static final Serializer<byte[][]> CONVERT_BT_MATRIX =
658             new BasicPrimitiveArrayOrMatrixSerializer<byte[][]>(FieldTypes.BYTE_8_MATRIX, 1, "byte_8_matrix", 2)
659             {
660                 @Override
661                 public int size(final byte[][] matrix)
662                 {
663                     return 8 + getElementSize() * matrix.length * matrix[0].length;
664                 }
665 
666                 @Override
667                 public void serialize(final byte[][] matrix, final byte[] buffer, final Pointer pointer,
668                         final EndianUtil endianUtil) throws SerializationException
669                 {
670                     int height = matrix.length;
671                     int width = matrix[0].length;
672                     endianUtil.encodeInt(height, buffer, pointer.getAndIncrement(4));
673                     endianUtil.encodeInt(width, buffer, pointer.getAndIncrement(4));
674                     for (int i = 0; i < height; i++)
675                     {
676                         Throw.when(matrix[i].length != width, SerializationException.class, "Jagged matrix is not allowed");
677                         for (int j = 0; j < width; j++)
678                         {
679                             buffer[pointer.getAndIncrement(getElementSize())] = matrix[i][j];
680                         }
681                     }
682                 }
683 
684                 @Override
685                 public byte[][] deSerialize(final byte[] buffer, final Pointer pointer, final EndianUtil endianUtil)
686                         throws SerializationException
687                 {
688                     int height = endianUtil.decodeInt(buffer, pointer.getAndIncrement(4));
689                     int width = endianUtil.decodeInt(buffer, pointer.getAndIncrement(4));
690                     byte[][] result = new byte[height][width];
691                     for (int i = 0; i < height; i++)
692                     {
693                         for (int j = 0; j < width; j++)
694                         {
695                             result[i][j] = buffer[pointer.getAndIncrement(getElementSize())];
696                         }
697                     }
698                     return result;
699                 }
700             };
701 
702     /** Converter for Byte matrix. */
703     private static final Serializer<Byte[][]> CONVERT_BYTE_MATRIX =
704             new ObjectMatrixSerializer<Byte>(FieldTypes.BYTE_8_MATRIX, 1, Byte.class, "Byte_8_matrix")
705             {
706                 @Override
707                 public void serializeElement(final Byte object, final byte[] buffer, final int offset,
708                         final EndianUtil endianUtil)
709                 {
710                     buffer[offset] = object;
711                 }
712 
713                 @Override
714                 public Byte deSerializeElement(final byte[] buffer, final int offset, final EndianUtil endianUtil)
715                 {
716                     return buffer[offset];
717                 }
718             };
719 
720     /** Converter for short matrix. */
721     private static final Serializer<short[][]> CONVERT_SHRT_MATRIX =
722             new BasicPrimitiveArrayOrMatrixSerializer<short[][]>(FieldTypes.SHORT_16_MATRIX, 2, "short_16_matrix", 2)
723             {
724                 @Override
725                 public int size(final short[][] matrix)
726                 {
727                     return 8 + getElementSize() * matrix.length * matrix[0].length;
728                 }
729 
730                 @Override
731                 public void serialize(final short[][] matrix, final byte[] buffer, final Pointer pointer,
732                         final EndianUtil endianUtil) throws SerializationException
733                 {
734                     int height = matrix.length;
735                     int width = matrix[0].length;
736                     endianUtil.encodeInt(height, buffer, pointer.getAndIncrement(4));
737                     endianUtil.encodeInt(width, buffer, pointer.getAndIncrement(4));
738                     for (int i = 0; i < height; i++)
739                     {
740                         Throw.when(matrix[i].length != width, SerializationException.class, "Jagged matrix is not allowed");
741                         for (int j = 0; j < width; j++)
742                         {
743                             endianUtil.encodeShort(matrix[i][j], buffer, pointer.getAndIncrement(getElementSize()));
744                         }
745                     }
746                 }
747 
748                 @Override
749                 public short[][] deSerialize(final byte[] buffer, final Pointer pointer, final EndianUtil endianUtil)
750                         throws SerializationException
751                 {
752                     int height = endianUtil.decodeInt(buffer, pointer.getAndIncrement(4));
753                     int width = endianUtil.decodeInt(buffer, pointer.getAndIncrement(4));
754                     short[][] result = new short[height][width];
755                     for (int i = 0; i < height; i++)
756                     {
757                         for (int j = 0; j < width; j++)
758                         {
759                             result[i][j] = endianUtil.decodeShort(buffer, pointer.getAndIncrement(getElementSize()));
760                         }
761                     }
762                     return result;
763                 }
764             };
765 
766     /** Converter for Short matrix. */
767     private static final Serializer<Short[][]> CONVERT_SHORT_MATRIX =
768             new ObjectMatrixSerializer<Short>(FieldTypes.SHORT_16_MATRIX, 2, Short.class, "Short_16_matrix")
769             {
770                 @Override
771                 public void serializeElement(final Short object, final byte[] buffer, final int offset,
772                         final EndianUtil endianUtil)
773                 {
774                     endianUtil.encodeShort(object, buffer, offset);
775                 }
776 
777                 @Override
778                 public Short deSerializeElement(final byte[] buffer, final int offset, final EndianUtil endianUtil)
779                 {
780                     return endianUtil.decodeShort(buffer, offset);
781                 }
782             };
783 
784     /** Converter for int matrix. */
785     private static final Serializer<int[][]> CONVERT_INT_MATRIX =
786             new BasicPrimitiveArrayOrMatrixSerializer<int[][]>(FieldTypes.INT_32_MATRIX, 4, "int_32_matrix", 2)
787             {
788                 @Override
789                 public int size(final int[][] matrix)
790                 {
791                     return 8 + getElementSize() * matrix.length * matrix[0].length;
792                 }
793 
794                 @Override
795                 public void serialize(final int[][] matrix, final byte[] buffer, final Pointer pointer,
796                         final EndianUtil endianUtil) throws SerializationException
797                 {
798                     int height = matrix.length;
799                     int width = matrix[0].length;
800                     endianUtil.encodeInt(height, buffer, pointer.getAndIncrement(4));
801                     endianUtil.encodeInt(width, buffer, pointer.getAndIncrement(4));
802                     for (int i = 0; i < height; i++)
803                     {
804                         Throw.when(matrix[i].length != width, SerializationException.class, "Jagged matrix is not allowed");
805                         for (int j = 0; j < width; j++)
806                         {
807                             endianUtil.encodeInt(matrix[i][j], buffer, pointer.getAndIncrement(getElementSize()));
808                         }
809                     }
810                 }
811 
812                 @Override
813                 public int[][] deSerialize(final byte[] buffer, final Pointer pointer, final EndianUtil endianUtil)
814                         throws SerializationException
815                 {
816                     int height = endianUtil.decodeInt(buffer, pointer.getAndIncrement(4));
817                     int width = endianUtil.decodeInt(buffer, pointer.getAndIncrement(4));
818                     int[][] result = new int[height][width];
819                     for (int i = 0; i < height; i++)
820                     {
821                         for (int j = 0; j < width; j++)
822                         {
823                             result[i][j] = endianUtil.decodeInt(buffer, pointer.getAndIncrement(getElementSize()));
824                         }
825                     }
826                     return result;
827                 }
828             };
829 
830     /** Converter for Integer matrix. */
831     private static final Serializer<Integer[][]> CONVERT_INTEGER_MATRIX =
832             new ObjectMatrixSerializer<Integer>(FieldTypes.INT_32_MATRIX, 4, Integer.class, "Integer_32_matrix")
833             {
834                 @Override
835                 public void serializeElement(final Integer object, final byte[] buffer, final int offset,
836                         final EndianUtil endianUtil)
837                 {
838                     endianUtil.encodeInt(object, buffer, offset);
839                 }
840 
841                 @Override
842                 public Integer deSerializeElement(final byte[] buffer, final int offset, final EndianUtil endianUtil)
843                 {
844                     return endianUtil.decodeInt(buffer, offset);
845                 }
846             };
847 
848     /** Converter for long matrix. */
849     private static final Serializer<long[][]> CONVERT_LNG_MATRIX =
850             new BasicPrimitiveArrayOrMatrixSerializer<long[][]>(FieldTypes.LONG_64_MATRIX, 8, "long_64_matrix", 2)
851             {
852                 @Override
853                 public int size(final long[][] matrix)
854                 {
855                     return 8 + getElementSize() * matrix.length * matrix[0].length;
856                 }
857 
858                 @Override
859                 public void serialize(final long[][] matrix, final byte[] buffer, final Pointer pointer,
860                         final EndianUtil endianUtil) throws SerializationException
861                 {
862                     int height = matrix.length;
863                     int width = matrix[0].length;
864                     endianUtil.encodeInt(height, buffer, pointer.getAndIncrement(4));
865                     endianUtil.encodeInt(width, buffer, pointer.getAndIncrement(4));
866                     for (int i = 0; i < height; i++)
867                     {
868                         Throw.when(matrix[i].length != width, SerializationException.class, "Jagged matrix is not allowed");
869                         for (int j = 0; j < width; j++)
870                         {
871                             endianUtil.encodeLong(matrix[i][j], buffer, pointer.getAndIncrement(getElementSize()));
872                         }
873                     }
874                 }
875 
876                 @Override
877                 public long[][] deSerialize(final byte[] buffer, final Pointer pointer, final EndianUtil endianUtil)
878                         throws SerializationException
879                 {
880                     int height = endianUtil.decodeInt(buffer, pointer.getAndIncrement(4));
881                     int width = endianUtil.decodeInt(buffer, pointer.getAndIncrement(4));
882                     long[][] result = new long[height][width];
883                     for (int i = 0; i < height; i++)
884                     {
885                         for (int j = 0; j < width; j++)
886                         {
887                             result[i][j] = endianUtil.decodeLong(buffer, pointer.getAndIncrement(getElementSize()));
888                         }
889                     }
890                     return result;
891                 }
892             };
893 
894     /** Converter for Long matrix. */
895     private static final Serializer<Long[][]> CONVERT_LONG_MATRIX =
896             new ObjectMatrixSerializer<Long>(FieldTypes.LONG_64_MATRIX, 8, Long.class, "Long_64_matrix")
897             {
898                 @Override
899                 public void serializeElement(final Long object, final byte[] buffer, final int offset,
900                         final EndianUtil endianUtil)
901                 {
902                     endianUtil.encodeLong(object, buffer, offset);
903                 }
904 
905                 @Override
906                 public Long deSerializeElement(final byte[] buffer, final int offset, final EndianUtil endianUtil)
907                 {
908                     return endianUtil.decodeLong(buffer, offset);
909                 }
910             };
911 
912     /** Converter for float matrix. */
913     private static final Serializer<float[][]> CONVERT_FLT_MATRIX =
914             new BasicPrimitiveArrayOrMatrixSerializer<float[][]>(FieldTypes.FLOAT_32_MATRIX, 4, "float_32_matrix", 2)
915             {
916                 @Override
917                 public int size(final float[][] matrix)
918                 {
919                     return 8 + getElementSize() * matrix.length * matrix[0].length;
920                 }
921 
922                 @Override
923                 public void serialize(final float[][] matrix, final byte[] buffer, final Pointer pointer,
924                         final EndianUtil endianUtil) throws SerializationException
925                 {
926                     int height = matrix.length;
927                     int width = matrix[0].length;
928                     endianUtil.encodeInt(height, buffer, pointer.getAndIncrement(4));
929                     endianUtil.encodeInt(width, buffer, pointer.getAndIncrement(4));
930                     for (int i = 0; i < height; i++)
931                     {
932                         Throw.when(matrix[i].length != width, SerializationException.class, "Jagged matrix is not allowed");
933                         for (int j = 0; j < width; j++)
934                         {
935                             endianUtil.encodeFloat(matrix[i][j], buffer, pointer.getAndIncrement(getElementSize()));
936                         }
937                     }
938                 }
939 
940                 @Override
941                 public float[][] deSerialize(final byte[] buffer, final Pointer pointer, final EndianUtil endianUtil)
942                         throws SerializationException
943                 {
944                     int height = endianUtil.decodeInt(buffer, pointer.getAndIncrement(4));
945                     int width = endianUtil.decodeInt(buffer, pointer.getAndIncrement(4));
946                     float[][] result = new float[height][width];
947                     for (int i = 0; i < height; i++)
948                     {
949                         for (int j = 0; j < width; j++)
950                         {
951                             result[i][j] = endianUtil.decodeFloat(buffer, pointer.getAndIncrement(getElementSize()));
952                         }
953                     }
954                     return result;
955                 }
956             };
957 
958     /** Converter for Float matrix. */
959     private static final Serializer<Float[][]> CONVERT_FLOAT_MATRIX =
960             new ObjectMatrixSerializer<Float>(FieldTypes.FLOAT_32_MATRIX, 4, Float.class, "Float_32_matrix")
961             {
962                 @Override
963                 public void serializeElement(final Float object, final byte[] buffer, final int offset,
964                         final EndianUtil endianUtil)
965                 {
966                     endianUtil.encodeFloat(object, buffer, offset);
967                 }
968 
969                 @Override
970                 public Float deSerializeElement(final byte[] buffer, final int offset, final EndianUtil endianUtil)
971                 {
972                     return endianUtil.decodeFloat(buffer, offset);
973                 }
974             };
975 
976     /** Converter for double matrix. */
977     private static final Serializer<double[][]> CONVERT_DBL_MATRIX =
978             new BasicPrimitiveArrayOrMatrixSerializer<double[][]>(FieldTypes.DOUBLE_64_MATRIX, 8, "double_64_matrix", 2)
979             {
980                 @Override
981                 public int size(final double[][] matrix)
982                 {
983                     return 8 + getElementSize() * matrix.length * matrix[0].length;
984                 }
985 
986                 @Override
987                 public void serialize(final double[][] matrix, final byte[] buffer, final Pointer pointer,
988                         final EndianUtil endianUtil) throws SerializationException
989                 {
990                     int height = matrix.length;
991                     int width = matrix[0].length;
992                     endianUtil.encodeInt(height, buffer, pointer.getAndIncrement(4));
993                     endianUtil.encodeInt(width, buffer, pointer.getAndIncrement(4));
994                     for (int i = 0; i < height; i++)
995                     {
996                         Throw.when(matrix[i].length != width, SerializationException.class, "Jagged matrix is not allowed");
997                         for (int j = 0; j < width; j++)
998                         {
999                             endianUtil.encodeDouble(matrix[i][j], buffer, pointer.getAndIncrement(getElementSize()));
1000                         }
1001                     }
1002                 }
1003 
1004                 @Override
1005                 public double[][] deSerialize(final byte[] buffer, final Pointer pointer, final EndianUtil endianUtil)
1006                         throws SerializationException
1007                 {
1008                     int height = endianUtil.decodeInt(buffer, pointer.getAndIncrement(4));
1009                     int width = endianUtil.decodeInt(buffer, pointer.getAndIncrement(4));
1010                     double[][] result = new double[height][width];
1011                     for (int i = 0; i < height; i++)
1012                     {
1013                         for (int j = 0; j < width; j++)
1014                         {
1015                             result[i][j] = endianUtil.decodeDouble(buffer, pointer.getAndIncrement(getElementSize()));
1016                         }
1017                     }
1018                     return result;
1019                 }
1020             };
1021 
1022     /** Converter for Double matrix. */
1023     private static final Serializer<Double[][]> CONVERT_DOUBLE_MATRIX =
1024             new ObjectMatrixSerializer<Double>(FieldTypes.DOUBLE_64_MATRIX, 8, Double.class, "Double_64_matrix")
1025             {
1026                 @Override
1027                 public void serializeElement(final Double object, final byte[] buffer, final int offset,
1028                         final EndianUtil endianUtil)
1029                 {
1030                     endianUtil.encodeDouble(object, buffer, offset);
1031                 }
1032 
1033                 @Override
1034                 public Double deSerializeElement(final byte[] buffer, final int offset, final EndianUtil endianUtil)
1035                 {
1036                     return endianUtil.decodeDouble(buffer, offset);
1037                 }
1038             };
1039 
1040     /** Converter for boolean matrix. */
1041     private static final Serializer<boolean[][]> CONVERT_BOOL_MATRIX =
1042             new BasicPrimitiveArrayOrMatrixSerializer<boolean[][]>(FieldTypes.BOOLEAN_8_MATRIX, 1, "boolean_8_matrix", 2)
1043             {
1044                 @Override
1045                 public int size(final boolean[][] matrix)
1046                 {
1047                     return 8 + getElementSize() * matrix.length * matrix[0].length;
1048                 }
1049 
1050                 @Override
1051                 public void serialize(final boolean[][] matrix, final byte[] buffer, final Pointer pointer,
1052                         final EndianUtil endianUtil) throws SerializationException
1053                 {
1054                     int height = matrix.length;
1055                     int width = matrix[0].length;
1056                     endianUtil.encodeInt(height, buffer, pointer.getAndIncrement(4));
1057                     endianUtil.encodeInt(width, buffer, pointer.getAndIncrement(4));
1058                     for (int i = 0; i < height; i++)
1059                     {
1060                         Throw.when(matrix[i].length != width, SerializationException.class, "Jagged matrix is not allowed");
1061                         for (int j = 0; j < width; j++)
1062                         {
1063                             buffer[pointer.getAndIncrement(getElementSize())] = (byte) (matrix[i][j] ? 1 : 0);
1064                         }
1065                     }
1066                 }
1067 
1068                 @Override
1069                 public boolean[][] deSerialize(final byte[] buffer, final Pointer pointer, final EndianUtil endianUtil)
1070                         throws SerializationException
1071                 {
1072                     int height = endianUtil.decodeInt(buffer, pointer.getAndIncrement(4));
1073                     int width = endianUtil.decodeInt(buffer, pointer.getAndIncrement(4));
1074                     boolean[][] result = new boolean[height][width];
1075                     for (int i = 0; i < height; i++)
1076                     {
1077                         for (int j = 0; j < width; j++)
1078                         {
1079                             result[i][j] = buffer[pointer.getAndIncrement(getElementSize())] != 0;
1080                         }
1081                     }
1082                     return result;
1083                 }
1084             };
1085 
1086     /** Converter for Boolean matrix. */
1087     private static final Serializer<Boolean[][]> CONVERT_BOOLEAN_MATRIX =
1088             new ObjectMatrixSerializer<Boolean>(FieldTypes.BOOLEAN_8_MATRIX, 1, Boolean.class, "Boolean_8_matrix")
1089             {
1090                 @Override
1091                 public void serializeElement(final Boolean object, final byte[] buffer, final int offset,
1092                         final EndianUtil endianUtil)
1093                 {
1094                     buffer[offset] = (byte) (object ? 1 : 0);
1095                 }
1096 
1097                 @Override
1098                 public Boolean deSerializeElement(final byte[] buffer, final int offset, final EndianUtil endianUtil)
1099                 {
1100                     return buffer[offset] != 0;
1101                 }
1102             };
1103 
1104     /** Converter for descendants of FloatScalar. */
1105     @SuppressWarnings({"rawtypes", "unchecked"})
1106     private static final Serializer<FloatScalar<?, ?>> CONVERT_DJUNITS_FLOAT_SCALAR = new FloatScalarSerializer();
1107 
1108     /** Converter for descendants of DoubleScalar. */
1109     @SuppressWarnings({"rawtypes", "unchecked"})
1110     private static final Serializer<DoubleScalar<?, ?>> CONVERT_DJUNITS_DOUBLE_SCALAR = new DoubleScalarSerializer();
1111 
1112     /** Converter for descendants of FloatVector. */
1113     @SuppressWarnings({"rawtypes", "unchecked"})
1114     private static final Serializer<FloatVector<?, ?, ?>> CONVERT_DJUNITS_FLOAT_VECTOR = new FloatVectorSerializer();
1115 
1116     /** Converter for descendants of DoubleVector. */
1117     @SuppressWarnings({"rawtypes", "unchecked"})
1118     private static final Serializer<DoubleVector<?, ?, ?>> CONVERT_DJUNITS_DOUBLE_VECTOR = new DoubleVectorSerializer();
1119 
1120     /** Converter for descendants of FloatMatrix. */
1121     @SuppressWarnings({"rawtypes", "unchecked"})
1122     private static final Serializer<FloatMatrix<?, ?, ?, ?>> CONVERT_DJUNITS_FLOAT_MATRIX = new FloatMatrixSerializer();
1123 
1124     /** Converter for descendants of DoubleMatrix. */
1125     @SuppressWarnings({"rawtypes", "unchecked"})
1126     private static final Serializer<DoubleMatrix> CONVERT_DJUNITS_DOUBLE_MATRIX = new DoubleMatrixSerializer();
1127 
1128     /** Serializer for array of DoubleVector. Each DoubleVector must have same size. */
1129     @SuppressWarnings({"rawtypes", "unchecked"})
1130     private static final Serializer<DoubleVector[]> CONVERT_DOUBLE_UNIT_COLUMN_VECTOR_ARRAY =
1131             new DoubleVectorArraySerializer();
1132 
1133     /** Converter for array of SerializebleObject using UTF16 for strings and characters. */
1134     private static final Serializer<SerializableObject<?>[]> COMPOUND_ARRAY_SERIALIZER_UTF16 =
1135             new ObjectSerializer<SerializableObject<?>[]>((byte) 120, "Compound")
1136             {
1137 
1138                 @SuppressWarnings({"unchecked", "rawtypes"})
1139                 @Override
1140                 public int size(final SerializableObject<?>[] objects) throws SerializationException
1141                 {
1142                     int result = 4 + 4;
1143                     SerializableObject<?> so = objects[0];
1144                     Object[] objectArray = so.exportAsList().toArray();
1145                     Serializer[] serializers = buildEncoderList(false, objectArray);
1146                     result += serializers.length;
1147                     for (int i = 0; i < objectArray.length; i++)
1148                     {
1149                         result += objects.length * serializers[i].size(objectArray[i]);
1150                     }
1151                     return result;
1152                 }
1153 
1154                 @SuppressWarnings({"unchecked", "rawtypes"})
1155                 @Override
1156                 public void serialize(final SerializableObject<?>[] objects, final byte[] buffer, final Pointer pointer,
1157                         final EndianUtil endianUtil) throws SerializationException
1158                 {
1159                     SerializableObject<?> so = objects[0];
1160                     Object[] objectArray = so.exportAsList().toArray();
1161                     endianUtil.encodeInt(objects.length, buffer, pointer.getAndIncrement(4));
1162                     endianUtil.encodeInt(objectArray.length, buffer, pointer.getAndIncrement(4));
1163                     Serializer[] serializers = buildEncoderList(false, objectArray);
1164                     for (int i = 0; i < objectArray.length; i++)
1165                     {
1166                         buffer[pointer.getAndIncrement(1)] = serializers[i].fieldType();
1167                     }
1168                     for (int i = 0; i < objects.length; i++)
1169                     {
1170                         List<Object> row = objects[i].exportAsList();
1171                         Throw.when(row.size() != objectArray.length, SerializationException.class,
1172                                 "List in row %d has %d elements which differs from the %d elements in row 0", i, row.size(),
1173                                 objectArray.length);
1174                         for (int j = 0; j < row.size(); j++)
1175                         {
1176                             serializers[j].serialize(row.get(j), buffer, pointer, endianUtil);
1177                         }
1178                     }
1179                 }
1180 
1181                 @Override
1182                 public SerializableObject<?>[] deSerialize(final byte[] buffer, final Pointer pointer,
1183                         final EndianUtil endianUtil) throws SerializationException
1184                 {
1185                     int arraySize = endianUtil.decodeInt(buffer, pointer.getAndIncrement(4));
1186                     int fieldCount = endianUtil.decodeInt(buffer, pointer.getAndIncrement(4));
1187                     Serializer<?>[] deSerializers = new Serializer[fieldCount];
1188                     for (int i = 0; i < fieldCount; i++)
1189                     {
1190                         Byte key = buffer[pointer.getAndIncrement(1)];
1191                         Serializer<?> deSerializer = PRIMITIVE_DATA_DECODERS.get(key);
1192                         Throw.whenNull(SerializationException.class, "No decoder for %d", key);
1193                         deSerializers[i] = deSerializer;
1194                     }
1195                     MinimalSerializableObject[] result = new MinimalSerializableObject[arraySize];
1196                     for (int i = 0; i < arraySize; i++)
1197                     {
1198                         List<Object> element = new ArrayList<>();
1199                         for (int j = 0; j < fieldCount; j++)
1200                         {
1201                             element.add(deSerializers[j].deSerialize(buffer, pointer, endianUtil));
1202                         }
1203                         result[i] = new MinimalSerializableObject(element);
1204                     }
1205                     return result;
1206                 }
1207             };
1208 
1209     /** Converter for array of SerializebleObject using UTF8 for strings and characters. */
1210     private static final Serializer<SerializableObject<?>[]> COMPOUND_ARRAY_SERIALIZER_UTF8 =
1211             new ObjectSerializer<SerializableObject<?>[]>((byte) 121, "Compound")
1212             {
1213 
1214                 @SuppressWarnings({"unchecked", "rawtypes"})
1215                 @Override
1216                 public int size(final SerializableObject<?>[] objects) throws SerializationException
1217                 {
1218                     int result = 4 + 4;
1219                     SerializableObject<?> so = objects[0];
1220                     Object[] objectArray = so.exportAsList().toArray();
1221                     Serializer[] serializers = buildEncoderList(true, objectArray);
1222                     result += serializers.length;
1223                     for (int i = 0; i < objectArray.length; i++)
1224                     {
1225                         result += objects.length * serializers[i].size(objectArray[i]);
1226                     }
1227                     return result;
1228                 }
1229 
1230                 @SuppressWarnings({"unchecked", "rawtypes"})
1231                 @Override
1232                 public void serialize(final SerializableObject<?>[] objects, final byte[] buffer, final Pointer pointer,
1233                         final EndianUtil endianUtil) throws SerializationException
1234                 {
1235                     SerializableObject<?> so = objects[0];
1236                     Object[] objectArray = so.exportAsList().toArray();
1237                     endianUtil.encodeInt(objects.length, buffer, pointer.getAndIncrement(4));
1238                     endianUtil.encodeInt(objectArray.length, buffer, pointer.getAndIncrement(4));
1239                     Serializer[] serializers = buildEncoderList(true, objectArray);
1240                     for (int i = 0; i < objectArray.length; i++)
1241                     {
1242                         buffer[pointer.getAndIncrement(1)] = serializers[i].fieldType();
1243                     }
1244                     for (int i = 0; i < objects.length; i++)
1245                     {
1246                         List<Object> row = objects[i].exportAsList();
1247                         Throw.when(row.size() != objectArray.length, SerializationException.class,
1248                                 "List in row %d has %d elements which differs from the %d elements in row 0", i, row.size(),
1249                                 objectArray.length);
1250                         for (int j = 0; j < row.size(); j++)
1251                         {
1252                             serializers[j].serialize(row.get(j), buffer, pointer, endianUtil);
1253                         }
1254                     }
1255                 }
1256 
1257                 @Override
1258                 public SerializableObject<?>[] deSerialize(final byte[] buffer, final Pointer pointer,
1259                         final EndianUtil endianUtil) throws SerializationException
1260                 {
1261                     int arraySize = endianUtil.decodeInt(buffer, pointer.getAndIncrement(4));
1262                     int fieldCount = endianUtil.decodeInt(buffer, pointer.getAndIncrement(4));
1263                     Serializer<?>[] deSerializers = new Serializer[fieldCount];
1264                     for (int i = 0; i < fieldCount; i++)
1265                     {
1266                         Byte key = buffer[pointer.getAndIncrement(1)];
1267                         Serializer<?> deSerializer = PRIMITIVE_DATA_DECODERS.get(key);
1268                         Throw.whenNull(SerializationException.class, "No decoder for %d", key);
1269                         deSerializers[i] = deSerializer;
1270                     }
1271                     MinimalSerializableObject[] result = new MinimalSerializableObject[arraySize];
1272                     for (int i = 0; i < arraySize; i++)
1273                     {
1274                         List<Object> element = new ArrayList<>();
1275                         for (int j = 0; j < fieldCount; j++)
1276                         {
1277                             element.add(deSerializers[j].deSerialize(buffer, pointer, endianUtil));
1278                         }
1279                         result[i] = new MinimalSerializableObject(element);
1280                     }
1281                     return result;
1282                 }
1283             };
1284 
1285     static
1286     {
1287         ENCODERS.put(Byte.class, CONVERT_BYTE);
1288         ENCODERS.put(byte.class, CONVERT_BYTE);
1289         ENCODERS.put(Short.class, CONVERT_SHORT);
1290         ENCODERS.put(short.class, CONVERT_SHORT);
1291         ENCODERS.put(Integer.class, CONVERT_INTEGER);
1292         ENCODERS.put(int.class, CONVERT_INTEGER);
1293         ENCODERS.put(Long.class, CONVERT_LONG);
1294         ENCODERS.put(long.class, CONVERT_LONG);
1295         ENCODERS.put(Float.class, CONVERT_FLOAT);
1296         ENCODERS.put(float.class, CONVERT_FLOAT);
1297         ENCODERS.put(Double.class, CONVERT_DOUBLE);
1298         ENCODERS.put(double.class, CONVERT_DOUBLE);
1299         ENCODERS.put(Boolean.class, CONVERT_BOOLEAN);
1300         ENCODERS.put(boolean.class, CONVERT_BOOLEAN);
1301         ENCODERS.put(Byte[].class, CONVERT_BYTE_ARRAY);
1302         ENCODERS.put(byte[].class, CONVERT_BT_ARRAY);
1303         ENCODERS.put(Short[].class, CONVERT_SHORT_ARRAY);
1304         ENCODERS.put(short[].class, CONVERT_SHRT_ARRAY);
1305         ENCODERS.put(Integer[].class, CONVERT_INTEGER_ARRAY);
1306         ENCODERS.put(int[].class, CONVERT_INT_ARRAY);
1307         ENCODERS.put(Long[].class, CONVERT_LONG_ARRAY);
1308         ENCODERS.put(long[].class, CONVERT_LNG_ARRAY);
1309         ENCODERS.put(Float[].class, CONVERT_FLOAT_ARRAY);
1310         ENCODERS.put(float[].class, CONVERT_FLT_ARRAY);
1311         ENCODERS.put(Double[].class, CONVERT_DOUBLE_ARRAY);
1312         ENCODERS.put(double[].class, CONVERT_DBL_ARRAY);
1313         ENCODERS.put(Boolean[].class, CONVERT_BOOLEAN_ARRAY);
1314         ENCODERS.put(boolean[].class, CONVERT_BOOL_ARRAY);
1315         ENCODERS.put(Byte[][].class, CONVERT_BYTE_MATRIX);
1316         ENCODERS.put(byte[][].class, CONVERT_BT_MATRIX);
1317         ENCODERS.put(Short[][].class, CONVERT_SHORT_MATRIX);
1318         ENCODERS.put(short[][].class, CONVERT_SHRT_MATRIX);
1319         ENCODERS.put(Integer[][].class, CONVERT_INTEGER_MATRIX);
1320         ENCODERS.put(int[][].class, CONVERT_INT_MATRIX);
1321         ENCODERS.put(Long[][].class, CONVERT_LONG_MATRIX);
1322         ENCODERS.put(long[][].class, CONVERT_LNG_MATRIX);
1323         ENCODERS.put(Float[][].class, CONVERT_FLOAT_MATRIX);
1324         ENCODERS.put(float[][].class, CONVERT_FLT_MATRIX);
1325         ENCODERS.put(Double[][].class, CONVERT_DOUBLE_MATRIX);
1326         ENCODERS.put(double[][].class, CONVERT_DBL_MATRIX);
1327         ENCODERS.put(Boolean[][].class, CONVERT_BOOLEAN_MATRIX);
1328         ENCODERS.put(boolean[][].class, CONVERT_BOOL_MATRIX);
1329 
1330         PRIMITIVE_DATA_DECODERS.put(CONVERT_BYTE.fieldType(), CONVERT_BYTE);
1331         PRIMITIVE_DATA_DECODERS.put(CONVERT_CHARACTER8.fieldType(), CONVERT_CHARACTER8);
1332         PRIMITIVE_DATA_DECODERS.put(CONVERT_CHARACTER16.fieldType(), CONVERT_CHARACTER16);
1333         PRIMITIVE_DATA_DECODERS.put(CONVERT_SHORT.fieldType(), CONVERT_SHORT);
1334         PRIMITIVE_DATA_DECODERS.put(CONVERT_INTEGER.fieldType(), CONVERT_INTEGER);
1335         PRIMITIVE_DATA_DECODERS.put(CONVERT_LONG.fieldType(), CONVERT_LONG);
1336         PRIMITIVE_DATA_DECODERS.put(CONVERT_FLOAT.fieldType(), CONVERT_FLOAT);
1337         PRIMITIVE_DATA_DECODERS.put(CONVERT_DOUBLE.fieldType(), CONVERT_DOUBLE);
1338         PRIMITIVE_DATA_DECODERS.put(CONVERT_BOOLEAN.fieldType(), CONVERT_BOOLEAN);
1339         PRIMITIVE_DATA_DECODERS.put(CONVERT_STRING8.fieldType(), CONVERT_STRING8);
1340         PRIMITIVE_DATA_DECODERS.put(CONVERT_STRING16.fieldType(), CONVERT_STRING16);
1341         PRIMITIVE_DATA_DECODERS.put(CONVERT_BT_ARRAY.fieldType(), CONVERT_BT_ARRAY);
1342         PRIMITIVE_DATA_DECODERS.put(CONVERT_SHRT_ARRAY.fieldType(), CONVERT_SHRT_ARRAY);
1343         PRIMITIVE_DATA_DECODERS.put(CONVERT_INT_ARRAY.fieldType(), CONVERT_INT_ARRAY);
1344         PRIMITIVE_DATA_DECODERS.put(CONVERT_LNG_ARRAY.fieldType(), CONVERT_LNG_ARRAY);
1345         PRIMITIVE_DATA_DECODERS.put(CONVERT_FLT_ARRAY.fieldType(), CONVERT_FLT_ARRAY);
1346         PRIMITIVE_DATA_DECODERS.put(CONVERT_DBL_ARRAY.fieldType(), CONVERT_DBL_ARRAY);
1347         PRIMITIVE_DATA_DECODERS.put(CONVERT_BOOL_ARRAY.fieldType(), CONVERT_BOOL_ARRAY);
1348         PRIMITIVE_DATA_DECODERS.put(CONVERT_BT_MATRIX.fieldType(), CONVERT_BT_MATRIX);
1349         PRIMITIVE_DATA_DECODERS.put(CONVERT_SHRT_MATRIX.fieldType(), CONVERT_SHRT_MATRIX);
1350         PRIMITIVE_DATA_DECODERS.put(CONVERT_INT_MATRIX.fieldType(), CONVERT_INT_MATRIX);
1351         PRIMITIVE_DATA_DECODERS.put(CONVERT_LNG_MATRIX.fieldType(), CONVERT_LNG_MATRIX);
1352         PRIMITIVE_DATA_DECODERS.put(CONVERT_FLT_MATRIX.fieldType(), CONVERT_FLT_MATRIX);
1353         PRIMITIVE_DATA_DECODERS.put(CONVERT_DBL_MATRIX.fieldType(), CONVERT_DBL_MATRIX);
1354         PRIMITIVE_DATA_DECODERS.put(CONVERT_BOOL_MATRIX.fieldType(), CONVERT_BOOL_MATRIX);
1355         PRIMITIVE_DATA_DECODERS.put(CONVERT_DJUNITS_FLOAT_SCALAR.fieldType(), CONVERT_DJUNITS_FLOAT_SCALAR);
1356         PRIMITIVE_DATA_DECODERS.put(CONVERT_DJUNITS_DOUBLE_SCALAR.fieldType(), CONVERT_DJUNITS_DOUBLE_SCALAR);
1357         PRIMITIVE_DATA_DECODERS.put(CONVERT_DJUNITS_FLOAT_VECTOR.fieldType(), CONVERT_DJUNITS_FLOAT_VECTOR);
1358         PRIMITIVE_DATA_DECODERS.put(CONVERT_DJUNITS_DOUBLE_VECTOR.fieldType(), CONVERT_DJUNITS_DOUBLE_VECTOR);
1359         PRIMITIVE_DATA_DECODERS.put(CONVERT_DJUNITS_FLOAT_MATRIX.fieldType(), CONVERT_DJUNITS_FLOAT_MATRIX);
1360         PRIMITIVE_DATA_DECODERS.put(CONVERT_DJUNITS_DOUBLE_MATRIX.fieldType(), CONVERT_DJUNITS_DOUBLE_MATRIX);
1361         PRIMITIVE_DATA_DECODERS.put(COMPOUND_ARRAY_SERIALIZER_UTF16.fieldType(), COMPOUND_ARRAY_SERIALIZER_UTF16);
1362         PRIMITIVE_DATA_DECODERS.put(COMPOUND_ARRAY_SERIALIZER_UTF8.fieldType(), COMPOUND_ARRAY_SERIALIZER_UTF8);
1363         PRIMITIVE_DATA_DECODERS.put(CONVERT_DOUBLE_UNIT_COLUMN_VECTOR_ARRAY.fieldType(),
1364                 CONVERT_DOUBLE_UNIT_COLUMN_VECTOR_ARRAY);
1365 
1366         OBJECT_DECODERS.put(CONVERT_BYTE.fieldType(), CONVERT_BYTE);
1367         OBJECT_DECODERS.put(CONVERT_CHARACTER8.fieldType(), CONVERT_CHARACTER8);
1368         OBJECT_DECODERS.put(CONVERT_CHARACTER16.fieldType(), CONVERT_CHARACTER16);
1369         OBJECT_DECODERS.put(CONVERT_SHORT.fieldType(), CONVERT_SHORT);
1370         OBJECT_DECODERS.put(CONVERT_INTEGER.fieldType(), CONVERT_INTEGER);
1371         OBJECT_DECODERS.put(CONVERT_LONG.fieldType(), CONVERT_LONG);
1372         OBJECT_DECODERS.put(CONVERT_FLOAT.fieldType(), CONVERT_FLOAT);
1373         OBJECT_DECODERS.put(CONVERT_DOUBLE.fieldType(), CONVERT_DOUBLE);
1374         OBJECT_DECODERS.put(CONVERT_BOOLEAN.fieldType(), CONVERT_BOOLEAN);
1375         OBJECT_DECODERS.put(CONVERT_STRING8.fieldType(), CONVERT_STRING8);
1376         OBJECT_DECODERS.put(CONVERT_STRING16.fieldType(), CONVERT_STRING16);
1377         OBJECT_DECODERS.put(CONVERT_BYTE_ARRAY.fieldType(), CONVERT_BYTE_ARRAY);
1378         OBJECT_DECODERS.put(CONVERT_SHORT_ARRAY.fieldType(), CONVERT_SHORT_ARRAY);
1379         OBJECT_DECODERS.put(CONVERT_INTEGER_ARRAY.fieldType(), CONVERT_INTEGER_ARRAY);
1380         OBJECT_DECODERS.put(CONVERT_LONG_ARRAY.fieldType(), CONVERT_LONG_ARRAY);
1381         OBJECT_DECODERS.put(CONVERT_FLOAT_ARRAY.fieldType(), CONVERT_FLOAT_ARRAY);
1382         OBJECT_DECODERS.put(CONVERT_DOUBLE_ARRAY.fieldType(), CONVERT_DOUBLE_ARRAY);
1383         OBJECT_DECODERS.put(CONVERT_BOOLEAN_ARRAY.fieldType(), CONVERT_BOOLEAN_ARRAY);
1384         OBJECT_DECODERS.put(CONVERT_BYTE_MATRIX.fieldType(), CONVERT_BYTE_MATRIX);
1385         OBJECT_DECODERS.put(CONVERT_SHORT_MATRIX.fieldType(), CONVERT_SHORT_MATRIX);
1386         OBJECT_DECODERS.put(CONVERT_INTEGER_MATRIX.fieldType(), CONVERT_INTEGER_MATRIX);
1387         OBJECT_DECODERS.put(CONVERT_LONG_MATRIX.fieldType(), CONVERT_LONG_MATRIX);
1388         OBJECT_DECODERS.put(CONVERT_FLOAT_MATRIX.fieldType(), CONVERT_FLOAT_MATRIX);
1389         OBJECT_DECODERS.put(CONVERT_DOUBLE_MATRIX.fieldType(), CONVERT_DOUBLE_MATRIX);
1390         OBJECT_DECODERS.put(CONVERT_BOOLEAN_MATRIX.fieldType(), CONVERT_BOOLEAN_MATRIX);
1391         OBJECT_DECODERS.put(CONVERT_DJUNITS_FLOAT_SCALAR.fieldType(), CONVERT_DJUNITS_FLOAT_SCALAR);
1392         OBJECT_DECODERS.put(CONVERT_DJUNITS_DOUBLE_SCALAR.fieldType(), CONVERT_DJUNITS_DOUBLE_SCALAR);
1393         OBJECT_DECODERS.put(CONVERT_DJUNITS_FLOAT_VECTOR.fieldType(), CONVERT_DJUNITS_FLOAT_VECTOR);
1394         OBJECT_DECODERS.put(CONVERT_DJUNITS_DOUBLE_VECTOR.fieldType(), CONVERT_DJUNITS_DOUBLE_VECTOR);
1395         OBJECT_DECODERS.put(CONVERT_DJUNITS_FLOAT_MATRIX.fieldType(), CONVERT_DJUNITS_FLOAT_MATRIX);
1396         OBJECT_DECODERS.put(CONVERT_DJUNITS_DOUBLE_MATRIX.fieldType(), CONVERT_DJUNITS_DOUBLE_MATRIX);
1397         OBJECT_DECODERS.put(COMPOUND_ARRAY_SERIALIZER_UTF16.fieldType(), COMPOUND_ARRAY_SERIALIZER_UTF16);
1398         OBJECT_DECODERS.put(COMPOUND_ARRAY_SERIALIZER_UTF8.fieldType(), COMPOUND_ARRAY_SERIALIZER_UTF8);
1399         OBJECT_DECODERS.put(CONVERT_DOUBLE_UNIT_COLUMN_VECTOR_ARRAY.fieldType(), CONVERT_DOUBLE_UNIT_COLUMN_VECTOR_ARRAY);
1400 
1401     }
1402 
1403     /** the UTF-8 charset. */
1404     protected static final Charset UTF8 = Charset.forName("UTF-8");
1405 
1406     /** the UTF-16 charset, big endian variant. */
1407     protected static final Charset UTF16 = Charset.forName("UTF-16BE");
1408 
1409     /**
1410      * Encode the object array into a byte[] message. Use UTF8 for the characters and for the String.
1411      * @param endianUtil EndianUtil; encoder to use for multi-byte values
1412      * @param content Object...; the objects to encode
1413      * @return the zeroMQ message to send as a byte array
1414      * @throws SerializationException on unknown data type
1415      */
1416     public static byte[] encodeUTF8(final EndianUtil endianUtil, final Object... content) throws SerializationException
1417     {
1418         return encode(true, endianUtil, content);
1419     }
1420 
1421     /**
1422      * Encode the object array into a byte[] message. Use UTF16 for the characters and for the String.
1423      * @param endianUtil EndianUtil; encoder for multi-byte values
1424      * @param content Object...; the objects to encode
1425      * @return the zeroMQ message to send as a byte array
1426      * @throws SerializationException on unknown data type
1427      */
1428     public static byte[] encodeUTF16(final EndianUtil endianUtil, final Object... content) throws SerializationException
1429     {
1430         return encode(false, endianUtil, content);
1431     }
1432 
1433     /**
1434      * Find the serializer for one object.
1435      * @param utf8 boolean; if true; use UTF8 encoding for characters and Strings; if false; use UTF16 encoding for characters
1436      *            and Strings
1437      * @param object Object; the object for which the serializer must be returned
1438      * @return Serializer; the serializer needed for <code>object</code>
1439      * @throws SerializationException when there is no known serializer for <code>object</code>
1440      */
1441     static Serializer<?> findEncoder(final boolean utf8, final Object object) throws SerializationException
1442     {
1443         Serializer<?> serializer = ENCODERS.get(object.getClass());
1444         if (serializer != null)
1445         {
1446             return serializer;
1447         }
1448         else if (object instanceof Character)
1449         {
1450             return utf8 ? CONVERT_CHARACTER8 : CONVERT_CHARACTER16;
1451         }
1452         else if (object instanceof String)
1453         {
1454             return utf8 ? CONVERT_STRING8 : CONVERT_STRING16;
1455         }
1456         else if (object instanceof FloatScalar)
1457         {
1458             return CONVERT_DJUNITS_FLOAT_SCALAR;
1459         }
1460         else if (object instanceof DoubleScalar)
1461         {
1462             return CONVERT_DJUNITS_DOUBLE_SCALAR;
1463         }
1464         else if (object instanceof FloatVector)
1465         {
1466             return CONVERT_DJUNITS_FLOAT_VECTOR;
1467         }
1468         else if (object instanceof DoubleVector)
1469         {
1470             return CONVERT_DJUNITS_DOUBLE_VECTOR;
1471         }
1472         else if (object instanceof FloatMatrix)
1473         {
1474             return CONVERT_DJUNITS_FLOAT_MATRIX;
1475         }
1476         else if (object instanceof DoubleMatrix)
1477         {
1478             return CONVERT_DJUNITS_DOUBLE_MATRIX;
1479         }
1480         else if (object instanceof SerializableObject[])
1481         {
1482             return utf8 ? COMPOUND_ARRAY_SERIALIZER_UTF8 : COMPOUND_ARRAY_SERIALIZER_UTF16;
1483         }
1484         else if (object instanceof DoubleVector[])
1485         {
1486             return CONVERT_DOUBLE_UNIT_COLUMN_VECTOR_ARRAY;
1487         }
1488         else
1489         {
1490             throw new SerializationException("Unhandled data type " + object.getClass());
1491         }
1492     }
1493 
1494     /**
1495      * Build the list of serializers corresponding to the data in an Object array.
1496      * @param utf8 boolean; if true; use UTF8 encoding for characters and Strings; if false; use UTF16 encoding for characters
1497      *            and Strings
1498      * @param content Object...; the objects for which the serializers must be returned
1499      * @return Serializer[]; array filled with the serializers needed for the objects in the Object array
1500      * @throws SerializationException when an object in <code>content</code> cannot be serialized
1501      */
1502     static Serializer<?>[] buildEncoderList(final boolean utf8, final Object... content) throws SerializationException
1503     {
1504         Serializer<?>[] result = new Serializer[content.length];
1505         for (int i = 0; i < content.length; i++)
1506         {
1507             Object object = content[i];
1508             result[i] = findEncoder(utf8, object);
1509         }
1510 
1511         return result;
1512     }
1513 
1514     /**
1515      * Encode the object array into a Big Endian message.
1516      * @param utf8 boolean; whether to encode String fields and characters in utf8 or not
1517      * @param endianUtil EndianUtil; encoder for multi-byte values
1518      * @param content Object...; the objects to encode
1519      * @return the zeroMQ message to send as a byte array
1520      * @throws SerializationException on unknown data type
1521      */
1522     @SuppressWarnings({"unchecked", "rawtypes"})
1523     private static byte[] encode(final boolean utf8, final EndianUtil endianUtil, final Object... content)
1524             throws SerializationException
1525     {
1526         Serializer[] serializers = buildEncoderList(utf8, content);
1527         // Pass one: compute total size
1528         int size = 0;
1529         for (int i = 0; i < serializers.length; i++)
1530         {
1531             size += serializers[i].sizeWithPrefix(content[i]);
1532         }
1533         // Allocate buffer
1534         byte[] message = new byte[size];
1535         // Pass 2 fill buffer
1536         Pointer pointer = new Pointer();
1537 
1538         for (int i = 0; i < serializers.length; i++)
1539         {
1540             serializers[i].serializeWithPrefix(content[i], message, pointer, endianUtil);
1541             // System.out.println("Expected increment: " + serializers[i].size(content[i]));
1542             // System.out.println(pointer);
1543         }
1544         Throw.when(pointer.get() != message.length, SerializationException.class, "Data size error (reserved %d, used %d)",
1545                 message.length, pointer.get());
1546         return message;
1547     }
1548 
1549     /**
1550      * Decode the message into an object array, constructing Java Primitive data arrays and matrices where possible.
1551      * @param buffer byte[]; the byte array to decode
1552      * @param endianUtil EndianUtil; decoder for multi-byte values
1553      * @return an array of objects of the right type
1554      * @throws SerializationException on unknown data type
1555      */
1556     public static Object[] decodeToPrimitiveDataTypes(final byte[] buffer, final EndianUtil endianUtil)
1557             throws SerializationException
1558     {
1559         return decode(buffer, PRIMITIVE_DATA_DECODERS, endianUtil);
1560     }
1561 
1562     /**
1563      * Decode the message into an object array, constructing Java Object arrays and matrices where possible.
1564      * @param buffer byte[]; the byte array to decode
1565      * @param endianUtil EndianUtil; decoder for multi-byte values
1566      * @return an array of objects of the right type
1567      * @throws SerializationException on unknown data type
1568      */
1569     public static Object[] decodeToObjectDataTypes(final byte[] buffer, final EndianUtil endianUtil)
1570             throws SerializationException
1571     {
1572         return decode(buffer, OBJECT_DECODERS, endianUtil);
1573     }
1574 
1575     /**
1576      * Decode the message into an object array.
1577      * @param buffer byte[]; the byte array to decode
1578      * @param decoderMap Map&lt;Byte, Serializer&lt;?&gt;&gt;; the map with decoders to use
1579      * @param endianUtil EndianUtil; decoder for multi-byte values
1580      * @return an array of objects of the right type
1581      * @throws SerializationException on unknown data type
1582      */
1583     @SuppressWarnings({"checkstyle:methodlength", "checkstyle:needbraces"})
1584     public static Object[] decode(final byte[] buffer, final Map<Byte, Serializer<?>> decoderMap, final EndianUtil endianUtil)
1585             throws SerializationException
1586     {
1587         List<Object> list = new ArrayList<>();
1588         Pointer pointer = new Pointer();
1589         while (pointer.get() < buffer.length)
1590         {
1591             Byte fieldType = buffer[pointer.getAndIncrement(1)];
1592             Serializer<?> serializer = decoderMap.get(fieldType);
1593             if (null == serializer)
1594             {
1595                 throw new SerializationException("Bad FieldType or no defined decoder for fieldType " + fieldType
1596                         + " at position " + (pointer.get() - 1));
1597             }
1598             else
1599             {
1600                 // System.out.println("Applying deserializer for " + serializer.dataClassName());
1601                 list.add(serializer.deSerialize(buffer, pointer, endianUtil));
1602             }
1603         }
1604         return list.toArray();
1605     }
1606 
1607     /**
1608      * Retrieve and decode a DJUNITS unit.
1609      * @param buffer byte[]; the encoded data
1610      * @param pointer Pointer; position in the encoded data where the unit is to be decoded from
1611      * @param endianUtil EndianUtil; decoder for multi-byte values
1612      * @return U; decoded Unit
1613      * @param <U> the unit type
1614      */
1615     @SuppressWarnings("unchecked")
1616     public static <U extends Unit<U>> U getUnit(final byte[] buffer, final Pointer pointer, final EndianUtil endianUtil)
1617     {
1618         SerializationUnits unitType = SerializationUnits.getUnitType(buffer[pointer.getAndIncrement(1)]);
1619         DisplayType displayType = DisplayType.getDisplayType(unitType, 0 + buffer[pointer.getAndIncrement(1)]);
1620         return (U) displayType.getDjunitsType();
1621     }
1622 
1623     /**
1624      * Minimal implementation of SerializableObject.
1625      */
1626     static class MinimalSerializableObject implements SerializableObject<MinimalSerializableObject>
1627     {
1628         /** The List that is returned by the <code>exportAsList</code> method. */
1629         private final List<Object> list;
1630 
1631         /**
1632          * Construct a new MinimalCompound object.
1633          * @param list List&lt;Object&gt;; the object list that is returned by <code>exportAsList</code> method
1634          */
1635         MinimalSerializableObject(final List<Object> list)
1636         {
1637             this.list = list;
1638         }
1639 
1640         @Override
1641         public List<Object> exportAsList()
1642         {
1643             return this.list;
1644         }
1645 
1646     }
1647 
1648 }