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.List; import org.simantics.databoard.binding.OptionalBinding; import org.simantics.databoard.binding.error.BindingException; 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; public class OptionalSerializer extends CompositeSerializer { OptionalBinding binding; public Serializer componentSerializer; boolean componentImmutable; Integer fixedSize; /** * Create optional serializer * * @param binding * @param componentSerializer (optional), can be set after */ public OptionalSerializer(OptionalBinding binding, Serializer componentSerializer) { super( IsReferableQuery.isReferable( binding.type() ) != Result.No ); this.componentSerializer = componentSerializer; this.binding = binding; this.componentImmutable = binding.getComponentBinding().isImmutable(); } @Override public void finalizeConstruction() { Integer fixedSizeOfComponent = componentSerializer.getConstantSize(); if (fixedSizeOfComponent!=null && fixedSizeOfComponent==0) { fixedSize = fixedSizeOfComponent + 1; } } @Override public Object deserialize(DataInput in, List identities) throws IOException { try { byte x = in.readByte(); if (x == 0) return binding.createNoValue(); else if (x == 1) { Object componentValue = componentSerializer.deserialize(in, identities); return binding.createValue(componentValue); } else throw new SerializationException("Unexpected marker for option "+x+" 0 or 1 expected."); } catch (BindingException e) { throw new IOException( e ); } } @Override public void deserializeTo(DataInput in, List identities, Object obj) throws IOException { try { byte x = in.readByte(); if (x == 0) { if (binding.hasValue(obj)) binding.setNoValue(obj); } else if (x == 1) { if (componentImmutable) { Object component = componentSerializer.deserialize(in, identities); binding.setValue(obj, component); } else { Object component = binding.hasValue(obj) ? binding.getValue(obj) : binding.componentBinding.createDefault(); component = componentSerializer.deserializeToTry(in, identities, component); binding.setValue(obj, component); } } else throw new SerializationException("Unexpected marker for option "+x+" 0 or 1 expected."); } catch (BindingException e) { throw new IOException( e ); } } @Override public void skip(DataInput in, List identities) throws IOException, SerializationException { int x = in.readByte(); if (x==1) componentSerializer.skip(in, identities); } @Override public void serialize(DataOutput out, TObjectIntHashMap identities, Object obj) throws IOException { try { if (!binding.hasValue(obj)) { out.write((byte)0); } else { out.write((byte)1); Object componentValue = binding.getValue(obj); componentSerializer.serialize(out, identities, componentValue); } } catch (BindingException e) { throw new IOException( e ); } } @Override public Integer getConstantSize() { return fixedSize; } @Override public int getSize(Object obj, TObjectIntHashMap identities) throws IOException { try { if (fixedSize!=null) return fixedSize; if (!binding.hasValue(obj)) return 1; Object componentValue = binding.getValue(obj); return 1 + componentSerializer.getSize(componentValue, identities); } catch (BindingException e) { throw new IOException( e ); } } @Override public int getMinSize() { return 1; } }