private void serialize( final @CheckForNull Type declaredType, @CheckForNull MetaData declaredMetaData, @CheckForNull GenericValue value, final ByteWriter destination) { boolean optional = (declaredType == null || declaredType.isOptional()); boolean polymorphic = (declaredMetaData == null || declaredMetaData.getMetaType().isPolymorphic()); if (value == null) { if (!optional) { throw new SerializerException("Non-optional entry '" + entryId + "' found to be null!"); } if (polymorphic) { serializerRepository .getEntityIdSerializer() .serialize(BootStrap.ID_NULL_REFERENCE, destination); } else { destination.putVarInt(0); // TODO optimize } return; } if (polymorphic) { if (declaredMetaData == null || declaredMetaData.getMetaType() != MetaType.ENTITY) { // Polymorphic type: Write actual type or 'null'-type. serializerRepository .getEntityIdSerializer() .serialize(value.getActualMetaDataId(), destination); } } else { // Non-polymorphic type: Do not write actual type. if (optional) { // As we do not serialize the type if the declared type is not // polymorphic we need to serialize whether it is present or // not. destination.putVarInt(1); // TODO optimize } } // TODO check that type matches declared type // TODO replace ValueVisitor by switch over MetaType for symmetry with // deserialize? // Or replace MetaData with subclasses (probably better). value.accept( new ValueVisitor() { @Override public void visit(PrimitiveValue primitive) { BinarySerializer<Object> serializer = serializerRepository.getPrimitiveSerializer(primitive.getActualMetaDataId()); serializer.serialize(primitive.getValue(), destination); } @Override public void visit(ValueObjectValue valueObject) { BinarySerializer<ObjectInfo> serializer = serializerRepository.getBinarySerializer(valueObject.getActualMetaDataId()); serializer.serialize(valueObject.getValue(), destination); } @Override public void visit(EntityIdValue entityReference) { serializerRepository .getEntityIdSerializer() .serialize(entityReference.getEntityId(), destination); } @Override public void visit(CollectionValue collection) { // Write element MetaDataId. serializerRepository .getEntityIdSerializer() .serialize(collection.getValueMetaDataId(), destination); // Write element count. destination.putVarInt(collection.getCount()); // Write custom collection implementation data. BinarySerializer<ObjectInfo> serializer = serializerRepository.getBinarySerializer(collection.getActualMetaDataId()); serializer.serialize(collection.getCollectionInfo(), destination); // Write all elements. for (GenericValue element : collection.getValues()) { Type elementType = (declaredType == null) ? null : declaredType.getElementType(); MetaData metaData = (elementType == null) ? null : serializerRepository.getMetaData(elementType.getMetaDataId()); if (element == GenericValue.nullValue()) { element = null; } serialize(elementType, metaData, element, destination); } } @Override public void visit(NullValue nullValue) { throw new IllegalArgumentException("Cannot deserialize NullValue!"); } }); }
@CheckForNull private GenericValue deserializeValue( ByteReader source, @CheckForNull Type declaredType, @CheckForNull MetaData declaredMetaData) { boolean optional = (declaredType == null || declaredType.isOptional()); MetaData actualMetaData = null; if (declaredMetaData == null || declaredMetaData.getMetaType().isPolymorphic()) { if ((declaredMetaData != null) && (declaredMetaData.getMetaType() == MetaType.ENTITY)) { actualMetaData = BootStrap.ENTITY_ID; } else { // Polymorphic type: Read actual type or 'null'-type. EntityId actualTypeId = serializerRepository.getEntityIdSerializer().deserialize(source); if (!BootStrap.ID_NULL_REFERENCE.equals(actualTypeId)) { actualMetaData = serializerRepository.getMetaData(actualTypeId); } } } else { // Non-polymorphic type: Do not read actual type. if (!optional || source.getVarInt() != 0) { actualMetaData = declaredMetaData; } } if (actualMetaData == null) { if (!optional) { throw new SerializerException("Non-optional entry found to be null!"); } return null; } switch (actualMetaData.getMetaType()) { case ENTITY: { EntityId entityId = serializerRepository.getEntityIdSerializer().deserialize(source); return BootStrap.ID_NULL_REFERENCE.equals(entityId) ? null : new EntityIdValue(entityId); } case PRIMITIVE: { Primitive primitive = Primitive.byEntityId(actualMetaData.getEntityId()); BinarySerializer<?> serializer = serializerRepository.getPrimitiveSerializer(actualMetaData.getEntityId()); return new PrimitiveValue(primitive, serializer.deserialize(source)); } case VALUE_OBJECT: { BinarySerializer<ObjectInfo> serializer = serializerRepository.getBinarySerializer(actualMetaData.getEntityId()); return new ValueObjectValue(serializer.deserialize(source)); } case COLLECTION: { // Read element MetaDataId. EntityId elementMetaDataId = serializerRepository.getEntityIdSerializer().deserialize(source); // Read element count. int count = MathUtil.longToInt(source.getVarInt()); // Read custom collection implementation data. BinarySerializer<ObjectInfo> serializer = serializerRepository.getBinarySerializer(actualMetaData.getEntityId()); ObjectInfo collectionInfo = serializer.deserialize(source); // Read all elements. ImmutableArrayList.Builder<GenericValue> builder = ImmutableArrayList.newBuilder(count); for (int i = 0; i < count; ++i) { Type elementType = (declaredType == null) ? null : declaredType.getElementType(); MetaData metaData = (elementType == null) ? null : serializerRepository.getMetaData(elementType.getMetaDataId()); GenericValue value = deserializeValue(source, elementType, metaData); builder.add((value == null) ? GenericValue.nullValue() : value); } return new CollectionValue(collectionInfo, elementMetaDataId, builder.build()); } default: throw new IllegalStateException("Unknown MetaType " + actualMetaData.getMetaType()); } }