+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
+\r
+import org.simantics.databoard.binding.Binding;\r
+import org.simantics.databoard.binding.RecordBinding;\r
+import org.simantics.databoard.binding.error.BindingException;\r
+import org.simantics.databoard.binding.reflection.ClassBinding;\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 GenericRecordSerializer extends CompositeSerializer {\r
+\r
+ RecordBinding binding;\r
+ public Serializer[] componentSerializers;\r
+ Integer fixedSize;\r
+ int minSize;\r
+ boolean createPartial;\r
+ \r
+ /**\r
+ * Field type for each field\r
+ * 0 - Object\r
+ * 1 - boolean\r
+ * 2 - byte\r
+ * 3 - int\r
+ * 4 - long\r
+ * 5 - float\r
+ * 6 - double\r
+ */\r
+ public int[] fieldType;\r
+ \r
+ /**\r
+ * \r
+ * @param binding\r
+ * @param componentSerializers (optional) can be set later\r
+ */\r
+ public GenericRecordSerializer(RecordBinding binding, Serializer[] componentSerializers) { \r
+ super( IsReferableQuery.isReferable( binding.type() ) != Result.No );\r
+ this.binding = binding; \r
+ this.componentSerializers = componentSerializers;\r
+ }\r
+ \r
+ @Override\r
+ public void finalizeConstruction() {\r
+ fixedSize = null;\r
+\r
+ createPartial = !binding.isImmutable();\r
+ \r
+ if ( binding instanceof ClassBinding ) {\r
+ ClassBinding cb = (ClassBinding) binding;\r
+ createPartial &= cb.ci.partialConstructionPossible;\r
+ }\r
+ \r
+ fieldType = new int[componentSerializers.length];\r
+ for (int i=0; i<componentSerializers.length; i++) {\r
+ Serializer cs = componentSerializers[i];\r
+ //createPartial &= !binding.getComponentBinding(i).isImmutable(); \r
+ minSize += cs.getMinSize();\r
+ Integer componentFixedSize = cs.getConstantSize();\r
+ if (componentFixedSize==null) {\r
+ fixedSize = null;\r
+ break;\r
+ }\r
+ fixedSize = fixedSize==null ? componentFixedSize : fixedSize+componentFixedSize;\r
+ \r
+ int type = 0;\r
+ if ( cs instanceof BooleanSerializer ) type = 1;\r
+ else if ( cs instanceof ByteSerializer ) type = 2;\r
+ else if ( cs instanceof IntSerializer ) type = 3;\r
+ else if ( cs instanceof LongSerializer ) type = 4;\r
+ else if ( cs instanceof FloatSerializer ) type = 5;\r
+ else if ( cs instanceof DoubleSerializer ) type = 6;\r
+ fieldType[i] = type;\r
+ }\r
+ \r
+// if ( binding instanceof ClassBinding ) {\r
+// ClassBinding cb = (ClassBinding) binding;\r
+// System.out.println(cb.ci.clazz.getName()+" = "+createPartial);\r
+// }\r
+ \r
+ }\r
+\r
+ @Override\r
+ public Object deserialize(DataInput in, List<Object> identities) throws IOException {\r
+// assertRemainingBytes(in, minSize);\r
+ try {\r
+ if (createPartial) {\r
+ Object obj = binding.createPartial();\r
+ deserializeTo(in, identities, obj);\r
+ return obj;\r
+ } else { \r
+ Object[] temp = new Object[componentSerializers.length];\r
+ for(int i=0;i<componentSerializers.length;++i) {\r
+ temp[i] = componentSerializers[i].deserialize(in, identities);\r
+ }\r
+ return binding.create(temp);\r
+ }\r
+ \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
+// assertRemainingBytes(in, minSize);\r
+ try {\r
+ for(int i=0;i<componentSerializers.length;++i) {\r
+ Serializer cs = componentSerializers[i];\r
+ int type = fieldType[i];\r
+ \r
+ switch (type) {\r
+ case 0:\r
+ Binding cb = binding.componentBindings[i];\r
+ boolean csImmutable = cb.isImmutable();\r
+ if (csImmutable) {\r
+ Object component = cs.deserialize(in, identities);\r
+ binding.setComponent(obj, i, component);\r
+ } else {\r
+ Object component = binding.getComponent(obj, i);\r
+ if ( component == null ) {\r
+ component = cs.deserialize(in, identities);\r
+ binding.setComponent(obj, i, component);\r
+ } else {\r
+ Object newComponent = cs.deserializeToTry(in, identities, component);\r
+ if (newComponent!=component) binding.setComponent(obj, i, newComponent);\r
+ }\r
+ }\r
+ break;\r
+ case 1:\r
+ binding.setBoolean(obj, i, ((BooleanSerializer)cs).getBoolean(in));\r
+ break;\r
+ case 2:\r
+ binding.setByte(obj, i, ((ByteSerializer)cs).getByte(in));\r
+ break;\r
+ case 3:\r
+ binding.setInt(obj, i, ((IntSerializer)cs).getInt(in));\r
+ break;\r
+ case 4:\r
+ binding.setLong(obj, i, ((LongSerializer)cs).getLong(in));\r
+ break;\r
+ case 5:\r
+ binding.setFloat(obj, i, ((FloatSerializer)cs).getFloat(in));\r
+ break;\r
+ case 6:\r
+ binding.setDouble(obj, i, ((DoubleSerializer)cs).getDouble(in));\r
+ break;\r
+ }\r
+ \r
+ }\r
+ } catch (BindingException e) {\r
+ throw new IOException( e ); \r
+ }\r
+ }\r
+\r
+ @Override\r
+ public void skip(DataInput in, List<Object> identities) throws IOException, SerializationException {\r
+ if (fixedSize != null) {\r
+ in.skipBytes(fixedSize);\r
+ } else {\r
+ for(int i=0;i<componentSerializers.length;++i)\r
+ componentSerializers[i].skip(in, identities); \r
+ }\r
+ } \r
+ \r
+ @Override\r
+ public void serialize(DataOutput out, TObjectIntHashMap<Object> identities, Object obj) throws IOException {\r
+ try {\r
+ for(int i=0;i<componentSerializers.length;++i) {\r
+ int type = fieldType[i];\r
+ Serializer cs = componentSerializers[i];\r
+ switch( type ) {\r
+ case 0: cs.serialize(out, identities, binding.getComponent(obj, i));\r
+ break; \r
+ case 1: ((BooleanSerializer)cs).putBoolean(out, binding.getBoolean(obj, i));\r
+ break;\r
+ case 2: ((ByteSerializer)cs).putByte(out, binding.getByte(obj, i));\r
+ break;\r
+ case 3: ((IntSerializer)cs).putInt(out, binding.getInt(obj, i));\r
+ break;\r
+ case 4: ((LongSerializer)cs).putLong(out, binding.getLong(obj, i));\r
+ break;\r
+ case 5: ((FloatSerializer)cs).putFloat(out, binding.getFloat(obj, i));\r
+ break;\r
+ case 6: ((DoubleSerializer)cs).putDouble(out, binding.getDouble(obj, i));\r
+ break;\r
+ }\r
+ }\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 result = 0;\r
+ for(int i=0;i<componentSerializers.length;++i)\r
+ result += componentSerializers[i].getSize( binding.getComponent(obj, i), identities ); \r
+ return result;\r
+ } catch (BindingException e) {\r
+ throw new IOException( e ); \r
+ }\r
+ }\r
+ \r
+ /**\r
+ * @return the minSize\r
+ */\r
+ public int getMinSize() {\r
+ return minSize;\r
+ }\r
+ \r
+}\r