-package org.simantics.databoard.serialization.impl;\r
-\r
-import gnu.trove.map.hash.TObjectIntHashMap;\r
-\r
-import java.io.DataInput;\r
-import java.io.DataOutput;\r
-import java.io.IOException;\r
-import java.util.List;\r
-import java.util.TreeSet;\r
-\r
-import org.simantics.databoard.binding.MapBinding;\r
-import org.simantics.databoard.binding.error.BindingException;\r
-import org.simantics.databoard.binding.util.IsReferableQuery;\r
-import org.simantics.databoard.binding.util.Result;\r
-import org.simantics.databoard.serialization.SerializationException;\r
-import org.simantics.databoard.serialization.Serializer;\r
-import org.simantics.databoard.serialization.Serializer.CompositeSerializer;\r
-\r
-public class MapSerializer extends CompositeSerializer {\r
-\r
- Integer fixedSizeOfKey, fixedSizeOfValue, fixedSizeOfEntry;\r
- public Serializer keySerializer, valueSerializer;\r
- MapBinding binding;\r
- \r
- /**\r
- * \r
- * @param binding\r
- * @param keySerializer (optional) can be set later\r
- * @param valueSerializer (optional) can be set later\r
- */\r
- public MapSerializer(MapBinding binding, Serializer keySerializer, Serializer valueSerializer) {\r
- super( IsReferableQuery.isReferable( binding.type() ) != Result.No );\r
- this.keySerializer = keySerializer;\r
- this.valueSerializer = valueSerializer;\r
- this.binding = binding;\r
- \r
- }\r
- \r
- @Override\r
- public void finalizeConstruction() {\r
- fixedSizeOfKey = keySerializer.getConstantSize();\r
- fixedSizeOfValue = valueSerializer.getConstantSize();\r
- fixedSizeOfEntry = (fixedSizeOfKey!=null && fixedSizeOfValue!=null) ? (fixedSizeOfKey+fixedSizeOfValue) : null; \r
- }\r
-\r
- @Override\r
- public Object deserialize(DataInput in, List<Object> identities) throws IOException{\r
- try {\r
- int length = in.readInt();\r
- if (length<0) throw new SerializationException("Cannot use negative array length");\r
- assertRemainingBytes(in, (long)length*((long)keySerializer.getMinSize()+(long)valueSerializer.getMinSize()));\r
- \r
- Object keys[] = new Object[length];\r
- Object values[] = new Object[length];\r
- \r
- for(int i=0;i<length;++i) {\r
- keys[i] = keySerializer.deserialize(in, identities);\r
- values[i] = valueSerializer.deserialize(in, identities); \r
- }\r
- return binding.create(keys, values);\r
- } catch (BindingException e) {\r
- throw new IOException( e ); \r
- } \r
- }\r
- \r
- @Override\r
- public void deserializeTo(DataInput in, List<Object> identities, Object obj) throws IOException {\r
- try {\r
- TreeSet<Object> oldKeys = new TreeSet<Object>( binding.getKeyBinding() );\r
- binding.getKeys(obj, oldKeys);\r
- \r
- int length = in.readInt();\r
- if (length<0) throw new SerializationException("Cannot use negative array length");\r
- assertRemainingBytes(in, (long)length*((long)keySerializer.getMinSize()+(long)valueSerializer.getMinSize()));\r
- \r
- for(int i=0;i<length;++i) {\r
- Object key = keySerializer.deserialize(in, identities);\r
- Object value = valueSerializer.deserialize(in, identities);\r
- binding.put(obj, key, value);\r
- oldKeys.remove(key);\r
- }\r
- \r
- // remove unused keys\r
- for (Object key : oldKeys)\r
- binding.remove(obj, key);\r
- } catch (BindingException e) {\r
- throw new IOException( e ); \r
- }\r
- \r
- }\r
- \r
- @Override\r
- public void skip(DataInput in, List<Object> identities)\r
- throws IOException, SerializationException {\r
- int length = in.readInt();\r
- if (fixedSizeOfEntry!=null) {\r
- in.skipBytes( length * fixedSizeOfEntry );\r
- return;\r
- }\r
- for(int i=0;i<length;++i) {\r
- if (fixedSizeOfKey!=null) {\r
- in.skipBytes(fixedSizeOfKey);\r
- } else {\r
- keySerializer.skip(in, identities);\r
- }\r
- \r
- if (fixedSizeOfValue!=null) {\r
- in.skipBytes(fixedSizeOfValue);\r
- } else {\r
- valueSerializer.skip(in, identities);\r
- }\r
- }\r
- }\r
-\r
- @Override\r
- public void serialize(DataOutput out, TObjectIntHashMap<Object> identities, Object map) throws IOException {\r
- try {\r
- int length = binding.size(map);\r
- //if (binding.isOrderedMap(map)) \r
- {\r
- Object[] keys = new Object[length];\r
- Object[] values = new Object[length];\r
- binding.getAll(map, keys, values);\r
- out.writeInt(length);\r
- for(int i=0;i<length;++i) {\r
- Object key = keys[i];\r
- Object value = values[i];\r
- keySerializer.serialize(out, identities, key);\r
- valueSerializer.serialize(out, identities, value); \r
- }\r
- }\r
- /*\r
- else {\r
- // Sort keys by putting into a treemap\r
- TreeMap<Object, Object> copyMap = new TreeMap<Object, Object>(binding.getKeyBinding());\r
- binding.getAll(map, copyMap);\r
- Iterator<Entry<Object, Object>> iter = copyMap.entrySet().iterator();\r
- putLength(out, length);\r
- while (iter.hasNext()) {\r
- Entry<Object, Object> e = iter.next();\r
- Object key = e.getKey();\r
- Object value = e.getValue();\r
- keySerializer.serialize(out, identities, key);\r
- valueSerializer.serialize(out, identities, value); \r
- }\r
- }*/\r
- } catch (BindingException e) {\r
- throw new IOException( e ); \r
- }\r
- }\r
-\r
- @Override\r
- public Integer getConstantSize() {\r
- return null;\r
- }\r
-\r
- @Override\r
- public int getSize(Object obj, TObjectIntHashMap<Object> identities) throws IOException {\r
- try {\r
- int length = binding.size(obj);\r
- if (fixedSizeOfEntry!=null)\r
- return 4 + fixedSizeOfEntry * length;\r
- int result = 4;\r
- Object keys[] = binding.getKeys(obj);\r
- for(int i=0;i<length;++i) {\r
- Object key = keys[i];\r
- Object value = binding.get(obj, key);\r
- result += keySerializer.getSize(key, identities);\r
- result += valueSerializer.getSize(value, identities);\r
- }\r
- return result;\r
- } catch (BindingException e) {\r
- throw new IOException( e ); \r
- }\r
- }\r
-\r
- @Override\r
- public int getMinSize() {\r
- return 4;\r
- }\r
- \r
-} \r
+package org.simantics.databoard.serialization.impl;
+
+import gnu.trove.map.hash.TObjectIntHashMap;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.List;
+import java.util.TreeSet;
+
+import org.simantics.databoard.binding.MapBinding;
+import org.simantics.databoard.binding.error.BindingException;
+import org.simantics.databoard.binding.util.IsReferableQuery;
+import org.simantics.databoard.binding.util.Result;
+import org.simantics.databoard.serialization.SerializationException;
+import org.simantics.databoard.serialization.Serializer;
+import org.simantics.databoard.serialization.Serializer.CompositeSerializer;
+
+public class MapSerializer extends CompositeSerializer {
+
+ Integer fixedSizeOfKey, fixedSizeOfValue, fixedSizeOfEntry;
+ public Serializer keySerializer, valueSerializer;
+ MapBinding binding;
+
+ /**
+ *
+ * @param binding
+ * @param keySerializer (optional) can be set later
+ * @param valueSerializer (optional) can be set later
+ */
+ public MapSerializer(MapBinding binding, Serializer keySerializer, Serializer valueSerializer) {
+ super( IsReferableQuery.isReferable( binding.type() ) != Result.No );
+ this.keySerializer = keySerializer;
+ this.valueSerializer = valueSerializer;
+ this.binding = binding;
+
+ }
+
+ @Override
+ public void finalizeConstruction() {
+ fixedSizeOfKey = keySerializer.getConstantSize();
+ fixedSizeOfValue = valueSerializer.getConstantSize();
+ fixedSizeOfEntry = (fixedSizeOfKey!=null && fixedSizeOfValue!=null) ? (fixedSizeOfKey+fixedSizeOfValue) : null;
+ }
+
+ @Override
+ public Object deserialize(DataInput in, List<Object> identities) throws IOException{
+ try {
+ int length = in.readInt();
+ if (length<0) throw new SerializationException("Cannot use negative array length");
+ assertRemainingBytes(in, (long)length*((long)keySerializer.getMinSize()+(long)valueSerializer.getMinSize()));
+
+ Object keys[] = new Object[length];
+ Object values[] = new Object[length];
+
+ for(int i=0;i<length;++i) {
+ keys[i] = keySerializer.deserialize(in, identities);
+ values[i] = valueSerializer.deserialize(in, identities);
+ }
+ return binding.create(keys, values);
+ } catch (BindingException e) {
+ throw new IOException( e );
+ }
+ }
+
+ @Override
+ public void deserializeTo(DataInput in, List<Object> identities, Object obj) throws IOException {
+ try {
+ TreeSet<Object> oldKeys = new TreeSet<Object>( binding.getKeyBinding() );
+ binding.getKeys(obj, oldKeys);
+
+ int length = in.readInt();
+ if (length<0) throw new SerializationException("Cannot use negative array length");
+ assertRemainingBytes(in, (long)length*((long)keySerializer.getMinSize()+(long)valueSerializer.getMinSize()));
+
+ for(int i=0;i<length;++i) {
+ Object key = keySerializer.deserialize(in, identities);
+ Object value = valueSerializer.deserialize(in, identities);
+ binding.put(obj, key, value);
+ oldKeys.remove(key);
+ }
+
+ // remove unused keys
+ for (Object key : oldKeys)
+ binding.remove(obj, key);
+ } catch (BindingException e) {
+ throw new IOException( e );
+ }
+
+ }
+
+ @Override
+ public void skip(DataInput in, List<Object> identities)
+ throws IOException, SerializationException {
+ int length = in.readInt();
+ if (fixedSizeOfEntry!=null) {
+ in.skipBytes( length * fixedSizeOfEntry );
+ return;
+ }
+ for(int i=0;i<length;++i) {
+ if (fixedSizeOfKey!=null) {
+ in.skipBytes(fixedSizeOfKey);
+ } else {
+ keySerializer.skip(in, identities);
+ }
+
+ if (fixedSizeOfValue!=null) {
+ in.skipBytes(fixedSizeOfValue);
+ } else {
+ valueSerializer.skip(in, identities);
+ }
+ }
+ }
+
+ @Override
+ public void serialize(DataOutput out, TObjectIntHashMap<Object> identities, Object map) throws IOException {
+ try {
+ int length = binding.size(map);
+ //if (binding.isOrderedMap(map))
+ {
+ Object[] keys = new Object[length];
+ Object[] values = new Object[length];
+ binding.getAll(map, keys, values);
+ out.writeInt(length);
+ for(int i=0;i<length;++i) {
+ Object key = keys[i];
+ Object value = values[i];
+ keySerializer.serialize(out, identities, key);
+ valueSerializer.serialize(out, identities, value);
+ }
+ }
+ /*
+ else {
+ // Sort keys by putting into a treemap
+ TreeMap<Object, Object> copyMap = new TreeMap<Object, Object>(binding.getKeyBinding());
+ binding.getAll(map, copyMap);
+ Iterator<Entry<Object, Object>> iter = copyMap.entrySet().iterator();
+ putLength(out, length);
+ while (iter.hasNext()) {
+ Entry<Object, Object> e = iter.next();
+ Object key = e.getKey();
+ Object value = e.getValue();
+ keySerializer.serialize(out, identities, key);
+ valueSerializer.serialize(out, identities, value);
+ }
+ }*/
+ } catch (BindingException e) {
+ throw new IOException( e );
+ }
+ }
+
+ @Override
+ public Integer getConstantSize() {
+ return null;
+ }
+
+ @Override
+ public int getSize(Object obj, TObjectIntHashMap<Object> identities) throws IOException {
+ try {
+ int length = binding.size(obj);
+ if (fixedSizeOfEntry!=null)
+ return 4 + fixedSizeOfEntry * length;
+ int result = 4;
+ Object keys[] = binding.getKeys(obj);
+ for(int i=0;i<length;++i) {
+ Object key = keys[i];
+ Object value = binding.get(obj, key);
+ result += keySerializer.getSize(key, identities);
+ result += valueSerializer.getSize(value, identities);
+ }
+ return result;
+ } catch (BindingException e) {
+ throw new IOException( e );
+ }
+ }
+
+ @Override
+ public int getMinSize() {
+ return 4;
+ }
+
+}