-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.ArrayList;\r
-import java.util.Iterator;\r
-import java.util.List;\r
-\r
-import org.simantics.databoard.binding.ArrayBinding;\r
-import org.simantics.databoard.binding.Binding;\r
-import org.simantics.databoard.binding.error.BindingException;\r
-import org.simantics.databoard.binding.impl.ArrayListBinding;\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
-import org.simantics.databoard.type.ArrayType;\r
-import org.simantics.databoard.util.Range;\r
-\r
-public class ArraySerializer extends CompositeSerializer {\r
-\r
- Range length;\r
- Integer fixedLength;\r
- Integer fixedSize;\r
- Integer fixedSizeOfComponent;\r
- public Serializer componentSerializer;\r
- boolean componentImmutable;\r
- ArrayBinding binding;\r
- DefaultValueIterator componentValueItr;\r
- \r
- /**\r
- * \r
- * @param binding\r
- * @param componentSerializer (optional) can be set after\r
- */\r
- public ArraySerializer(ArrayBinding binding, Serializer componentSerializer) {\r
- super( IsReferableQuery.isReferable( binding.type() ) != Result.No );\r
- ArrayType arrayType = (ArrayType) binding.type();\r
- this.componentSerializer = componentSerializer;\r
- this.binding = binding;\r
- this.length = arrayType.getLength();\r
- this.componentImmutable = binding.getComponentBinding().isImmutable();\r
- this.componentValueItr = new DefaultValueIterator();\r
- componentValueItr.binding = binding.componentBinding;\r
- }\r
- \r
- @Override\r
- public void finalizeConstruction() {\r
- fixedSizeOfComponent = componentSerializer.getConstantSize();\r
- if (fixedSizeOfComponent!=null && length!=null && length.getLower().equals(length.getUpper()) && length.getLower().getValue()!=null)\r
- {\r
- fixedLength = length.getLower().getValue().intValue();\r
- fixedSize = fixedLength * fixedSizeOfComponent;\r
- } \r
- }\r
-\r
- @Override\r
- public Object deserialize(DataInput in, List<Object> identities) throws IOException {\r
- try {\r
- int length = fixedLength != null ? fixedLength : in.readInt(); \r
- if (length<0) throw new SerializationException("Cannot use negative array length");\r
- assertRemainingBytes(in, ((long)length)*componentSerializer.getMinSize()); \r
-\r
- ArrayList<Object> temp = new ArrayList<Object>(length);\r
- for(int i=0;i<length;++i)\r
- temp.add(componentSerializer.deserialize(in, identities));\r
- return binding instanceof ArrayListBinding ? temp : binding.create(temp);\r
- } catch (BindingException e) {\r
- throw new IOException( e ); \r
- }\r
- }\r
- \r
- public Object deserializeToTry(DataInput in, List<Object> identities, Object obj) throws IOException\r
- {\r
- try {\r
- int length = fixedLength != null ? fixedLength : in.readInt();\r
- if (length<0) throw new SerializationException("Cannot use negative array length");\r
- assertRemainingBytes(in, ((long)length)*componentSerializer.getMinSize()); \r
- \r
- int oldLen = binding.size(obj);\r
- \r
- if (oldLen!=length) {\r
- if ( binding.isResizable() ) {\r
- binding.setSize(obj, length);\r
- } else {\r
- obj = binding.create(length, componentValueItr);\r
- oldLen = length;\r
- }\r
- }\r
- \r
- if ( componentImmutable ) {\r
- for(int i=0;i<length;i++) {\r
- Object component = componentSerializer.deserialize(in, identities);\r
- binding.set(obj, i, component);\r
- }\r
- } else {\r
- for(int i=0;i<length;i++) {\r
- Object component = binding.get(obj, i);\r
- component = componentSerializer.deserializeToTry(in, identities, component);\r
- binding.set(obj, i, component); \r
- }\r
- if (oldLen>length) binding.setSize(obj, length); \r
- }\r
- \r
- return obj;\r
- } catch (BindingException e) {\r
- throw new IOException( e ); \r
- }\r
- \r
- } \r
-\r
- @Override\r
- public void deserializeTo(DataInput in, List<Object> identities, Object obj) throws IOException {\r
- try {\r
- int length = fixedLength != null ? fixedLength : in.readInt();\r
- if (length<0) throw new SerializationException("Cannot use negative array length");\r
- assertRemainingBytes(in, ((long)length)*componentSerializer.getMinSize()); \r
- \r
- int oldLen = binding.size(obj);\r
- \r
- if (oldLen!=length) {\r
- if ( binding.isResizable() ) {\r
- binding.setSize(obj, length);\r
- } else {\r
- throw new IOException("Cannot resize array");\r
- }\r
- }\r
- \r
- if ( componentImmutable ) {\r
- for(int i=0;i<length;i++) {\r
- Object component = componentSerializer.deserialize(in, identities);\r
- binding.set(obj, i, component);\r
- }\r
- } else {\r
- for(int i=0;i<length;i++) {\r
- Object component = binding.get(obj, i);\r
- component = componentSerializer.deserializeToTry(in, identities, component);\r
- binding.set(obj, i, component); \r
- }\r
- if (oldLen>length) binding.setSize(obj, length); \r
- }\r
- } catch (BindingException e) {\r
- throw new IOException( e ); \r
- } \r
- }\r
- \r
- @Override\r
- public void skip(DataInput in, List<Object> identities)\r
- throws IOException {\r
- if (fixedSize!=null) {\r
- in.skipBytes(fixedSize);\r
- return;\r
- }\r
- int length = fixedLength != null ? fixedLength : in.readInt();\r
- \r
- if (fixedSizeOfComponent!=null) {\r
- // Skip all elements\r
- in.skipBytes(length * fixedSizeOfComponent);\r
- } else {\r
- // Skip each element individualy\r
- for(int i=0;i<length;++i)\r
- componentSerializer.skip(in, identities);\r
- }\r
- }\r
-\r
- @Override\r
- public void serialize(DataOutput out, TObjectIntHashMap<Object> identities, Object obj) throws IOException {\r
- try {\r
- int length = binding.size(obj);\r
- if (fixedLength==null) {\r
- out.writeInt(length);\r
- } else { \r
- if (length!=fixedLength)\r
- throw new SerializationException("Unexpected array length "+length+", size is restricted to "+fixedLength);\r
- }\r
- \r
- // Serialize elements\r
- for(int i=0;i<length;++i)\r
- componentSerializer.serialize(out, identities, binding.get(obj, i));\r
- } catch (BindingException e) {\r
- throw new IOException( e ); \r
- }\r
- }\r
-\r
- @Override\r
- public Integer getConstantSize() {\r
- return fixedSize;\r
- }\r
-\r
- @Override\r
- public int getSize(Object obj, TObjectIntHashMap<Object> identities) throws IOException {\r
- try {\r
- if (fixedSize!=null) return fixedSize;\r
- int length = binding.size(obj);\r
- if (fixedSizeOfComponent!=null)\r
- return 4 + fixedSizeOfComponent * length;\r
- int result = 4;\r
- for(int i=0;i<length;++i)\r
- result += componentSerializer.getSize(binding.get(obj, i), identities);\r
- return result;\r
- } catch (BindingException e) {\r
- throw new IOException( e ); \r
- }\r
- }\r
-\r
- @Override\r
- public int getMinSize() {\r
- return fixedSize != null ? fixedSize : 4;\r
- }\r
- \r
-}\r
-\r
-/**\r
- * Default value iterator iterates default values.\r
- * The iterator is infinite.\r
- * \r
- * @author toni.kalajainen\r
- */\r
-class DefaultValueIterator implements Iterator<Object> {\r
- \r
- Binding binding;\r
-\r
- @Override\r
- public boolean hasNext() {\r
- return true;\r
- }\r
-\r
- @Override\r
- public Object next() {\r
- try {\r
- return binding.createDefault();\r
- } catch (BindingException e) {\r
- return null;\r
- }\r
- }\r
-\r
- @Override\r
- public void remove() {\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.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.simantics.databoard.binding.ArrayBinding;
+import org.simantics.databoard.binding.Binding;
+import org.simantics.databoard.binding.error.BindingException;
+import org.simantics.databoard.binding.impl.ArrayListBinding;
+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;
+import org.simantics.databoard.type.ArrayType;
+import org.simantics.databoard.util.Range;
+
+public class ArraySerializer extends CompositeSerializer {
+
+ Range length;
+ Integer fixedLength;
+ Integer fixedSize;
+ Integer fixedSizeOfComponent;
+ public Serializer componentSerializer;
+ boolean componentImmutable;
+ ArrayBinding binding;
+ DefaultValueIterator componentValueItr;
+
+ /**
+ *
+ * @param binding
+ * @param componentSerializer (optional) can be set after
+ */
+ public ArraySerializer(ArrayBinding binding, Serializer componentSerializer) {
+ super( IsReferableQuery.isReferable( binding.type() ) != Result.No );
+ ArrayType arrayType = (ArrayType) binding.type();
+ this.componentSerializer = componentSerializer;
+ this.binding = binding;
+ this.length = arrayType.getLength();
+ this.componentImmutable = binding.getComponentBinding().isImmutable();
+ this.componentValueItr = new DefaultValueIterator();
+ componentValueItr.binding = binding.componentBinding;
+ }
+
+ @Override
+ public void finalizeConstruction() {
+ fixedSizeOfComponent = componentSerializer.getConstantSize();
+ if (fixedSizeOfComponent!=null && length!=null && length.getLower().equals(length.getUpper()) && length.getLower().getValue()!=null)
+ {
+ fixedLength = length.getLower().getValue().intValue();
+ fixedSize = fixedLength * fixedSizeOfComponent;
+ }
+ }
+
+ @Override
+ public Object deserialize(DataInput in, List<Object> identities) throws IOException {
+ try {
+ int length = fixedLength != null ? fixedLength : in.readInt();
+ if (length<0) throw new SerializationException("Cannot use negative array length");
+ assertRemainingBytes(in, ((long)length)*componentSerializer.getMinSize());
+
+ ArrayList<Object> temp = new ArrayList<Object>(length);
+ for(int i=0;i<length;++i)
+ temp.add(componentSerializer.deserialize(in, identities));
+ return binding instanceof ArrayListBinding ? temp : binding.create(temp);
+ } catch (BindingException e) {
+ throw new IOException( e );
+ }
+ }
+
+ public Object deserializeToTry(DataInput in, List<Object> identities, Object obj) throws IOException
+ {
+ try {
+ int length = fixedLength != null ? fixedLength : in.readInt();
+ if (length<0) throw new SerializationException("Cannot use negative array length");
+ assertRemainingBytes(in, ((long)length)*componentSerializer.getMinSize());
+
+ int oldLen = binding.size(obj);
+
+ if (oldLen!=length) {
+ if ( binding.isResizable() ) {
+ binding.setSize(obj, length);
+ } else {
+ obj = binding.create(length, componentValueItr);
+ oldLen = length;
+ }
+ }
+
+ if ( componentImmutable ) {
+ for(int i=0;i<length;i++) {
+ Object component = componentSerializer.deserialize(in, identities);
+ binding.set(obj, i, component);
+ }
+ } else {
+ for(int i=0;i<length;i++) {
+ Object component = binding.get(obj, i);
+ component = componentSerializer.deserializeToTry(in, identities, component);
+ binding.set(obj, i, component);
+ }
+ if (oldLen>length) binding.setSize(obj, length);
+ }
+
+ return obj;
+ } catch (BindingException e) {
+ throw new IOException( e );
+ }
+
+ }
+
+ @Override
+ public void deserializeTo(DataInput in, List<Object> identities, Object obj) throws IOException {
+ try {
+ int length = fixedLength != null ? fixedLength : in.readInt();
+ if (length<0) throw new SerializationException("Cannot use negative array length");
+ assertRemainingBytes(in, ((long)length)*componentSerializer.getMinSize());
+
+ int oldLen = binding.size(obj);
+
+ if (oldLen!=length) {
+ if ( binding.isResizable() ) {
+ binding.setSize(obj, length);
+ } else {
+ throw new IOException("Cannot resize array");
+ }
+ }
+
+ if ( componentImmutable ) {
+ for(int i=0;i<length;i++) {
+ Object component = componentSerializer.deserialize(in, identities);
+ binding.set(obj, i, component);
+ }
+ } else {
+ for(int i=0;i<length;i++) {
+ Object component = binding.get(obj, i);
+ component = componentSerializer.deserializeToTry(in, identities, component);
+ binding.set(obj, i, component);
+ }
+ if (oldLen>length) binding.setSize(obj, length);
+ }
+ } catch (BindingException e) {
+ throw new IOException( e );
+ }
+ }
+
+ @Override
+ public void skip(DataInput in, List<Object> identities)
+ throws IOException {
+ if (fixedSize!=null) {
+ in.skipBytes(fixedSize);
+ return;
+ }
+ int length = fixedLength != null ? fixedLength : in.readInt();
+
+ if (fixedSizeOfComponent!=null) {
+ // Skip all elements
+ in.skipBytes(length * fixedSizeOfComponent);
+ } else {
+ // Skip each element individualy
+ for(int i=0;i<length;++i)
+ componentSerializer.skip(in, identities);
+ }
+ }
+
+ @Override
+ public void serialize(DataOutput out, TObjectIntHashMap<Object> identities, Object obj) throws IOException {
+ try {
+ int length = binding.size(obj);
+ if (fixedLength==null) {
+ out.writeInt(length);
+ } else {
+ if (length!=fixedLength)
+ throw new SerializationException("Unexpected array length "+length+", size is restricted to "+fixedLength);
+ }
+
+ // Serialize elements
+ for(int i=0;i<length;++i)
+ componentSerializer.serialize(out, identities, binding.get(obj, i));
+ } catch (BindingException e) {
+ throw new IOException( e );
+ }
+ }
+
+ @Override
+ public Integer getConstantSize() {
+ return fixedSize;
+ }
+
+ @Override
+ public int getSize(Object obj, TObjectIntHashMap<Object> identities) throws IOException {
+ try {
+ if (fixedSize!=null) return fixedSize;
+ int length = binding.size(obj);
+ if (fixedSizeOfComponent!=null)
+ return 4 + fixedSizeOfComponent * length;
+ int result = 4;
+ for(int i=0;i<length;++i)
+ result += componentSerializer.getSize(binding.get(obj, i), identities);
+ return result;
+ } catch (BindingException e) {
+ throw new IOException( e );
+ }
+ }
+
+ @Override
+ public int getMinSize() {
+ return fixedSize != null ? fixedSize : 4;
+ }
+
+}
+
+/**
+ * Default value iterator iterates default values.
+ * The iterator is infinite.
+ *
+ * @author toni.kalajainen
+ */
+class DefaultValueIterator implements Iterator<Object> {
+
+ Binding binding;
+
+ @Override
+ public boolean hasNext() {
+ return true;
+ }
+
+ @Override
+ public Object next() {
+ try {
+ return binding.createDefault();
+ } catch (BindingException e) {
+ return null;
+ }
+ }
+
+ @Override
+ public void remove() {
+ }
+
}
\ No newline at end of file