Home | History | Annotate | Download | only in serializers
      1 /*
      2  * Copyright (c) 2009-2010 jMonkeyEngine, Java Game Networking
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are
      7  * met:
      8  *
      9  * * Redistributions of source code must retain the above copyright
     10  *   notice, this list of conditions and the following disclaimer.
     11  *
     12  * * Redistributions in binary form must reproduce the above copyright
     13  *   notice, this list of conditions and the following disclaimer in the
     14  *   documentation and/or other materials provided with the distribution.
     15  *
     16  * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
     17  *   may be used to endorse or promote products derived from this software
     18  *   without specific prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 package com.jme3.network.serializing.serializers;
     34 
     35 import com.jme3.network.serializing.Serializer;
     36 import java.io.IOException;
     37 import java.lang.reflect.Array;
     38 import java.lang.reflect.Modifier;
     39 import java.nio.ByteBuffer;
     40 
     41 /**
     42  * Array serializer
     43  *
     44  * @author Nathan Sweet
     45  */
     46 @SuppressWarnings("unchecked")
     47 public class ArraySerializer extends Serializer {
     48     private int[] getDimensions (Object array) {
     49         int depth = 0;
     50         Class nextClass = array.getClass().getComponentType();
     51         while (nextClass != null) {
     52             depth++;
     53             nextClass = nextClass.getComponentType();
     54         }
     55         int[] dimensions = new int[depth];
     56         dimensions[0] = Array.getLength(array);
     57         if (depth > 1) collectDimensions(array, 1, dimensions);
     58         return dimensions;
     59     }
     60 
     61     private void collectDimensions (Object array, int dimension, int[] dimensions) {
     62         boolean elementsAreArrays = dimension < dimensions.length - 1;
     63         for (int i = 0, s = Array.getLength(array); i < s; i++) {
     64             Object element = Array.get(array, i);
     65             if (element == null) continue;
     66             dimensions[dimension] = Math.max(dimensions[dimension], Array.getLength(element));
     67             if (elementsAreArrays) collectDimensions(element, dimension + 1, dimensions);
     68         }
     69     }
     70 
     71     public <T> T readObject(ByteBuffer data, Class<T> c) throws IOException {
     72         byte dimensionCount = data.get();
     73         if (dimensionCount == 0)
     74             return null;
     75 
     76         int[] dimensions = new int[dimensionCount];
     77         for (int i = 0; i < dimensionCount; i++)
     78                 dimensions[i] = data.getInt();
     79 
     80         Serializer elementSerializer = null;
     81 
     82         Class elementClass = c;
     83         while (elementClass.getComponentType() != null)
     84             elementClass = elementClass.getComponentType();
     85 
     86         if (Modifier.isFinal(elementClass.getModifiers())) elementSerializer = Serializer.getSerializer(elementClass);
     87         // Create array and read in the data.
     88         T array = (T)Array.newInstance(elementClass, dimensions);
     89         readArray(elementSerializer, elementClass, data, array, 0, dimensions);
     90         return array;
     91     }
     92 
     93     public void writeObject(ByteBuffer buffer, Object object) throws IOException {
     94         if (object == null){
     95             buffer.put((byte)0);
     96             return;
     97         }
     98 
     99         int[] dimensions = getDimensions(object);
    100         buffer.put((byte)dimensions.length);
    101         for (int dimension : dimensions) buffer.putInt(dimension);
    102         Serializer elementSerializer = null;
    103 
    104         Class elementClass = object.getClass();
    105         while (elementClass.getComponentType() != null) {
    106             elementClass = elementClass.getComponentType();
    107         }
    108 
    109         if (Modifier.isFinal(elementClass.getModifiers())) elementSerializer = Serializer.getSerializer(elementClass);
    110         writeArray(elementSerializer, buffer, object, 0, dimensions.length);
    111     }
    112 
    113     private void writeArray(Serializer elementSerializer, ByteBuffer buffer, Object array, int dimension, int dimensionCount) throws IOException {
    114         int length = Array.getLength(array);
    115         if (dimension > 0) {
    116             buffer.putInt(length);
    117         }
    118         // Write array data.
    119         boolean elementsAreArrays = dimension < dimensionCount - 1;
    120         for (int i = 0; i < length; i++) {
    121             Object element = Array.get(array, i);
    122             if (elementsAreArrays) {
    123                 if (element != null) writeArray(elementSerializer, buffer, element, dimension + 1, dimensionCount);
    124             } else if (elementSerializer != null) {
    125                 elementSerializer.writeObject(buffer, element);
    126             } else {
    127                 // Each element could be a different type. Store the class with the object.
    128                 Serializer.writeClassAndObject(buffer, element);
    129             }
    130         }
    131     }
    132 
    133     private void readArray (Serializer elementSerializer, Class elementClass, ByteBuffer buffer, Object array, int dimension, int[] dimensions) throws IOException {
    134         boolean elementsAreArrays = dimension < dimensions.length - 1;
    135         int length;
    136         if (dimension == 0) {
    137             length = dimensions[0];
    138         } else {
    139             length = buffer.getInt();
    140         }
    141         for (int i = 0; i < length; i++) {
    142             if (elementsAreArrays) {
    143                 // Nested array.
    144                 Object element = Array.get(array, i);
    145                 if (element != null) readArray(elementSerializer, elementClass, buffer, element, dimension + 1, dimensions);
    146             } else if (elementSerializer != null) {
    147                 // Use same converter (and class) for all elements.
    148                 Array.set(array, i, elementSerializer.readObject(buffer, elementClass));
    149             } else {
    150                 // Each element could be a different type. Look up the class with the object.
    151                 Array.set(array, i, Serializer.readClassAndObject(buffer));
    152             }
    153         }
    154     }
    155 }
    156