1 package org.simantics.databoard.serialization.impl;
3 import gnu.trove.map.hash.TObjectIntHashMap;
5 import java.io.DataInput;
6 import java.io.DataOutput;
7 import java.io.IOException;
8 import java.util.ArrayList;
9 import java.util.Iterator;
10 import java.util.List;
12 import org.simantics.databoard.binding.ArrayBinding;
13 import org.simantics.databoard.binding.Binding;
14 import org.simantics.databoard.binding.error.BindingException;
15 import org.simantics.databoard.binding.impl.ArrayListBinding;
16 import org.simantics.databoard.binding.util.IsReferableQuery;
17 import org.simantics.databoard.binding.util.Result;
18 import org.simantics.databoard.serialization.SerializationException;
19 import org.simantics.databoard.serialization.Serializer;
20 import org.simantics.databoard.serialization.Serializer.CompositeSerializer;
21 import org.simantics.databoard.type.ArrayType;
22 import org.simantics.databoard.util.Range;
24 public class ArraySerializer extends CompositeSerializer {
29 Integer fixedSizeOfComponent;
30 public Serializer componentSerializer;
31 boolean componentImmutable;
33 DefaultValueIterator componentValueItr;
38 * @param componentSerializer (optional) can be set after
40 public ArraySerializer(ArrayBinding binding, Serializer componentSerializer) {
41 super( IsReferableQuery.isReferable( binding.type() ) != Result.No );
42 ArrayType arrayType = (ArrayType) binding.type();
43 this.componentSerializer = componentSerializer;
44 this.binding = binding;
45 this.length = arrayType.getLength();
46 this.componentImmutable = binding.getComponentBinding().isImmutable();
47 this.componentValueItr = new DefaultValueIterator();
48 componentValueItr.binding = binding.componentBinding;
52 public void finalizeConstruction() {
53 fixedSizeOfComponent = componentSerializer.getConstantSize();
54 if (fixedSizeOfComponent!=null && length!=null && length.getLower().equals(length.getUpper()) && length.getLower().getValue()!=null)
56 fixedLength = length.getLower().getValue().intValue();
57 fixedSize = fixedLength * fixedSizeOfComponent;
62 public Object deserialize(DataInput in, List<Object> identities) throws IOException {
64 int length = fixedLength != null ? fixedLength : in.readInt();
65 if (length<0) throw new SerializationException("Cannot use negative array length");
66 assertRemainingBytes(in, ((long)length)*componentSerializer.getMinSize());
68 ArrayList<Object> temp = new ArrayList<Object>(length);
69 for(int i=0;i<length;++i)
70 temp.add(componentSerializer.deserialize(in, identities));
71 return binding instanceof ArrayListBinding ? temp : binding.create(temp);
72 } catch (BindingException e) {
73 throw new IOException( e );
77 public Object deserializeToTry(DataInput in, List<Object> identities, Object obj) throws IOException
80 int length = fixedLength != null ? fixedLength : in.readInt();
81 if (length<0) throw new SerializationException("Cannot use negative array length");
82 assertRemainingBytes(in, ((long)length)*componentSerializer.getMinSize());
84 int oldLen = binding.size(obj);
87 if ( binding.isResizable() ) {
88 binding.setSize(obj, length);
90 obj = binding.create(length, componentValueItr);
95 if ( componentImmutable ) {
96 for(int i=0;i<length;i++) {
97 Object component = componentSerializer.deserialize(in, identities);
98 binding.set(obj, i, component);
101 for(int i=0;i<length;i++) {
102 Object component = binding.get(obj, i);
103 component = componentSerializer.deserializeToTry(in, identities, component);
104 binding.set(obj, i, component);
106 if (oldLen>length) binding.setSize(obj, length);
110 } catch (BindingException e) {
111 throw new IOException( e );
117 public void deserializeTo(DataInput in, List<Object> identities, Object obj) throws IOException {
119 int length = fixedLength != null ? fixedLength : in.readInt();
120 if (length<0) throw new SerializationException("Cannot use negative array length");
121 assertRemainingBytes(in, ((long)length)*componentSerializer.getMinSize());
123 int oldLen = binding.size(obj);
125 if (oldLen!=length) {
126 if ( binding.isResizable() ) {
127 binding.setSize(obj, length);
129 throw new IOException("Cannot resize array");
133 if ( componentImmutable ) {
134 for(int i=0;i<length;i++) {
135 Object component = componentSerializer.deserialize(in, identities);
136 binding.set(obj, i, component);
139 for(int i=0;i<length;i++) {
140 Object component = binding.get(obj, i);
141 component = componentSerializer.deserializeToTry(in, identities, component);
142 binding.set(obj, i, component);
144 if (oldLen>length) binding.setSize(obj, length);
146 } catch (BindingException e) {
147 throw new IOException( e );
152 public void skip(DataInput in, List<Object> identities)
154 if (fixedSize!=null) {
155 in.skipBytes(fixedSize);
158 int length = fixedLength != null ? fixedLength : in.readInt();
160 if (fixedSizeOfComponent!=null) {
162 in.skipBytes(length * fixedSizeOfComponent);
164 // Skip each element individualy
165 for(int i=0;i<length;++i)
166 componentSerializer.skip(in, identities);
171 public void serialize(DataOutput out, TObjectIntHashMap<Object> identities, Object obj) throws IOException {
173 int length = binding.size(obj);
174 if (fixedLength==null) {
175 out.writeInt(length);
177 if (length!=fixedLength)
178 throw new SerializationException("Unexpected array length "+length+", size is restricted to "+fixedLength);
181 // Serialize elements
182 for(int i=0;i<length;++i)
183 componentSerializer.serialize(out, identities, binding.get(obj, i));
184 } catch (BindingException e) {
185 throw new IOException( e );
190 public Integer getConstantSize() {
195 public int getSize(Object obj, TObjectIntHashMap<Object> identities) throws IOException {
197 if (fixedSize!=null) return fixedSize;
198 int length = binding.size(obj);
199 if (fixedSizeOfComponent!=null)
200 return 4 + fixedSizeOfComponent * length;
202 for(int i=0;i<length;++i)
203 result += componentSerializer.getSize(binding.get(obj, i), identities);
205 } catch (BindingException e) {
206 throw new IOException( e );
211 public int getMinSize() {
212 return fixedSize != null ? fixedSize : 4;
218 * Default value iterator iterates default values.
219 * The iterator is infinite.
221 * @author toni.kalajainen
223 class DefaultValueIterator implements Iterator<Object> {
228 public boolean hasNext() {
233 public Object next() {
235 return binding.createDefault();
236 } catch (BindingException e) {
242 public void remove() {