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