1 /* 2 * Copyright (c) 2009-2010 jMonkeyEngine 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 com.jme3.network.serializing.SerializerRegistration; 37 import java.io.IOException; 38 import java.nio.ByteBuffer; 39 import java.util.HashMap; 40 import java.util.Iterator; 41 import java.util.Map; 42 import java.util.Map.Entry; 43 import java.util.Set; 44 import java.util.logging.Level; 45 46 public class MapSerializer extends Serializer { 47 48 /* 49 50 Structure: 51 52 struct Map { 53 INT length 54 BYTE flags = { 0x01 = all keys have the same type, 55 0x02 = all values have the same type } 56 if (flags has 0x01 set) 57 SHORT keyType 58 if (flags has 0x02 set) 59 SHORT valType 60 61 struct MapEntry[length] entries { 62 if (flags does not have 0x01 set) 63 SHORT keyType 64 OBJECT key 65 66 if (flags does not have 0x02 set) 67 SHORT valType 68 OBJECT value 69 } 70 } 71 72 */ 73 74 @SuppressWarnings("unchecked") 75 public <T> T readObject(ByteBuffer data, Class<T> c) throws IOException { 76 int length = data.getInt(); 77 78 Map map; 79 try { 80 map = (Map)c.newInstance(); 81 } catch (Exception e) { 82 log.log(Level.WARNING, "[Serializer][???] Could not determine map type. Using HashMap."); 83 map = new HashMap(); 84 } 85 86 if (length == 0) return (T)map; 87 88 int flags = data.get() & 0xff; 89 boolean uniqueKeys = (flags & 0x01) == 0; 90 boolean uniqueVals = (flags & 0x02) == 0; 91 92 Class keyClazz = null; 93 Class valClazz = null; 94 Serializer keySerial = null; 95 Serializer valSerial = null; 96 if (!uniqueKeys){ 97 SerializerRegistration reg = Serializer.readClass(data); 98 keyClazz = reg.getType(); 99 keySerial = reg.getSerializer(); 100 } 101 if (!uniqueVals){ 102 SerializerRegistration reg = Serializer.readClass(data); 103 valClazz = reg.getType(); 104 valSerial = reg.getSerializer(); 105 } 106 107 for (int i = 0; i < length; i++){ 108 Object key; 109 Object value; 110 if (uniqueKeys){ 111 key = Serializer.readClassAndObject(data); 112 }else{ 113 key = keySerial.readObject(data, keyClazz); 114 } 115 if (uniqueVals){ 116 value = Serializer.readClassAndObject(data); 117 }else{ 118 value = valSerial.readObject(data, valClazz); 119 } 120 121 map.put(key, value); 122 } 123 124 return (T)map; 125 } 126 127 @SuppressWarnings("unchecked") 128 public void writeObject(ByteBuffer buffer, Object object) throws IOException { 129 Map map = (Map)object; 130 int length = map.size(); 131 132 buffer.putInt(length); 133 if (length == 0) return; 134 135 136 Set<Entry> entries = map.entrySet(); 137 138 Iterator<Entry> it = entries.iterator(); 139 140 Entry entry = it.next(); 141 Class keyClass = entry.getKey().getClass(); 142 Class valClass = entry.getValue().getClass(); 143 while (it.hasNext()) { 144 entry = it.next(); 145 146 if (entry.getKey().getClass() != keyClass){ 147 keyClass = null; 148 if (valClass == null) 149 break; 150 } 151 if (entry.getValue().getClass() != valClass){ 152 valClass = null; 153 if (keyClass == null) 154 break; 155 } 156 } 157 158 boolean uniqueKeys = keyClass == null; 159 boolean uniqueVals = valClass == null; 160 int flags = 0; 161 if (!uniqueKeys) flags |= 0x01; 162 if (!uniqueVals) flags |= 0x02; 163 buffer.put( (byte) flags ); 164 165 Serializer keySerial = null, valSerial = null; 166 if (!uniqueKeys){ 167 Serializer.writeClass(buffer, keyClass); 168 keySerial = Serializer.getSerializer(keyClass); 169 } 170 if (!uniqueVals){ 171 Serializer.writeClass(buffer, valClass); 172 valSerial = Serializer.getSerializer(valClass); 173 } 174 175 it = entries.iterator(); 176 while (it.hasNext()) { 177 entry = it.next(); 178 if (uniqueKeys){ 179 Serializer.writeClassAndObject(buffer, entry.getKey()); 180 }else{ 181 keySerial.writeObject(buffer, entry.getKey()); 182 } 183 if (uniqueVals){ 184 Serializer.writeClassAndObject(buffer, entry.getValue()); 185 }else{ 186 valSerial.writeObject(buffer, entry.getValue()); 187 } 188 } 189 } 190 } 191