1 package org.simantics.databoard.serialization.impl;
\r
3 import gnu.trove.map.hash.TObjectIntHashMap;
\r
5 import java.io.DataInput;
\r
6 import java.io.DataOutput;
\r
7 import java.io.IOException;
\r
8 import java.util.List;
\r
9 import java.util.TreeSet;
\r
11 import org.simantics.databoard.binding.MapBinding;
\r
12 import org.simantics.databoard.binding.error.BindingException;
\r
13 import org.simantics.databoard.binding.util.IsReferableQuery;
\r
14 import org.simantics.databoard.binding.util.Result;
\r
15 import org.simantics.databoard.serialization.SerializationException;
\r
16 import org.simantics.databoard.serialization.Serializer;
\r
17 import org.simantics.databoard.serialization.Serializer.CompositeSerializer;
\r
19 public class MapSerializer extends CompositeSerializer {
\r
21 Integer fixedSizeOfKey, fixedSizeOfValue, fixedSizeOfEntry;
\r
22 public Serializer keySerializer, valueSerializer;
\r
28 * @param keySerializer (optional) can be set later
\r
29 * @param valueSerializer (optional) can be set later
\r
31 public MapSerializer(MapBinding binding, Serializer keySerializer, Serializer valueSerializer) {
\r
32 super( IsReferableQuery.isReferable( binding.type() ) != Result.No );
\r
33 this.keySerializer = keySerializer;
\r
34 this.valueSerializer = valueSerializer;
\r
35 this.binding = binding;
\r
40 public void finalizeConstruction() {
\r
41 fixedSizeOfKey = keySerializer.getConstantSize();
\r
42 fixedSizeOfValue = valueSerializer.getConstantSize();
\r
43 fixedSizeOfEntry = (fixedSizeOfKey!=null && fixedSizeOfValue!=null) ? (fixedSizeOfKey+fixedSizeOfValue) : null;
\r
47 public Object deserialize(DataInput in, List<Object> identities) throws IOException{
\r
49 int length = in.readInt();
\r
50 if (length<0) throw new SerializationException("Cannot use negative array length");
\r
51 assertRemainingBytes(in, (long)length*((long)keySerializer.getMinSize()+(long)valueSerializer.getMinSize()));
\r
53 Object keys[] = new Object[length];
\r
54 Object values[] = new Object[length];
\r
56 for(int i=0;i<length;++i) {
\r
57 keys[i] = keySerializer.deserialize(in, identities);
\r
58 values[i] = valueSerializer.deserialize(in, identities);
\r
60 return binding.create(keys, values);
\r
61 } catch (BindingException e) {
\r
62 throw new IOException( e );
\r
67 public void deserializeTo(DataInput in, List<Object> identities, Object obj) throws IOException {
\r
69 TreeSet<Object> oldKeys = new TreeSet<Object>( binding.getKeyBinding() );
\r
70 binding.getKeys(obj, oldKeys);
\r
72 int length = in.readInt();
\r
73 if (length<0) throw new SerializationException("Cannot use negative array length");
\r
74 assertRemainingBytes(in, (long)length*((long)keySerializer.getMinSize()+(long)valueSerializer.getMinSize()));
\r
76 for(int i=0;i<length;++i) {
\r
77 Object key = keySerializer.deserialize(in, identities);
\r
78 Object value = valueSerializer.deserialize(in, identities);
\r
79 binding.put(obj, key, value);
\r
80 oldKeys.remove(key);
\r
83 // remove unused keys
\r
84 for (Object key : oldKeys)
\r
85 binding.remove(obj, key);
\r
86 } catch (BindingException e) {
\r
87 throw new IOException( e );
\r
93 public void skip(DataInput in, List<Object> identities)
\r
94 throws IOException, SerializationException {
\r
95 int length = in.readInt();
\r
96 if (fixedSizeOfEntry!=null) {
\r
97 in.skipBytes( length * fixedSizeOfEntry );
\r
100 for(int i=0;i<length;++i) {
\r
101 if (fixedSizeOfKey!=null) {
\r
102 in.skipBytes(fixedSizeOfKey);
\r
104 keySerializer.skip(in, identities);
\r
107 if (fixedSizeOfValue!=null) {
\r
108 in.skipBytes(fixedSizeOfValue);
\r
110 valueSerializer.skip(in, identities);
\r
116 public void serialize(DataOutput out, TObjectIntHashMap<Object> identities, Object map) throws IOException {
\r
118 int length = binding.size(map);
\r
119 //if (binding.isOrderedMap(map))
\r
121 Object[] keys = new Object[length];
\r
122 Object[] values = new Object[length];
\r
123 binding.getAll(map, keys, values);
\r
124 out.writeInt(length);
\r
125 for(int i=0;i<length;++i) {
\r
126 Object key = keys[i];
\r
127 Object value = values[i];
\r
128 keySerializer.serialize(out, identities, key);
\r
129 valueSerializer.serialize(out, identities, value);
\r
134 // Sort keys by putting into a treemap
\r
135 TreeMap<Object, Object> copyMap = new TreeMap<Object, Object>(binding.getKeyBinding());
\r
136 binding.getAll(map, copyMap);
\r
137 Iterator<Entry<Object, Object>> iter = copyMap.entrySet().iterator();
\r
138 putLength(out, length);
\r
139 while (iter.hasNext()) {
\r
140 Entry<Object, Object> e = iter.next();
\r
141 Object key = e.getKey();
\r
142 Object value = e.getValue();
\r
143 keySerializer.serialize(out, identities, key);
\r
144 valueSerializer.serialize(out, identities, value);
\r
147 } catch (BindingException e) {
\r
148 throw new IOException( e );
\r
153 public Integer getConstantSize() {
\r
158 public int getSize(Object obj, TObjectIntHashMap<Object> identities) throws IOException {
\r
160 int length = binding.size(obj);
\r
161 if (fixedSizeOfEntry!=null)
\r
162 return 4 + fixedSizeOfEntry * length;
\r
164 Object keys[] = binding.getKeys(obj);
\r
165 for(int i=0;i<length;++i) {
\r
166 Object key = keys[i];
\r
167 Object value = binding.get(obj, key);
\r
168 result += keySerializer.getSize(key, identities);
\r
169 result += valueSerializer.getSize(value, identities);
\r
172 } catch (BindingException e) {
\r
173 throw new IOException( e );
\r
178 public int getMinSize() {
\r