Пример #1
0
        /// <summary>
        /// Builds a deserializer for the Confluent wire format.
        /// </summary>
        /// <param name="id">
        /// A schema ID that all payloads must be serialized with. If a received schema ID does not
        /// match this ID, <see cref="InvalidDataException" /> will be thrown.
        /// </param>
        /// <param name="schema">
        /// The schema to build the Avro deserializer from.
        /// </param>
        protected virtual IDeserializer <T> Build <T>(int id, string schema)
        {
            var deserialize = DeserializerBuilder.BuildDelegate <T>(SchemaReader.Read(schema));

            return(new DelegateDeserializer <T>(stream =>
            {
                var bytes = new byte[4];

                if (stream.ReadByte() != 0x00 || stream.Read(bytes, 0, bytes.Length) != bytes.Length)
                {
                    throw new InvalidDataException("Data does not conform to the Confluent wire format.");
                }

                if (BitConverter.IsLittleEndian)
                {
                    Array.Reverse(bytes);
                }

                var received = BitConverter.ToInt32(bytes, 0);

                if (received != id)
                {
                    throw new InvalidDataException($"The received schema ({received}) does not match the specified schema ({id}).");
                }

                return deserialize(stream);
            }));
        }
Пример #2
0
        /// <summary>
        /// Deserialize a message. (See <see cref="IAsyncDeserializer{T}.DeserializeAsync(ReadOnlyMemory{byte}, bool, SerializationContext)" />.)
        /// </summary>
        public virtual async Task <T> DeserializeAsync(ReadOnlyMemory <byte> data, bool isNull, SerializationContext context)
        {
            using (var stream = new MemoryStream(data.ToArray(), false))
            {
                var bytes = new byte[4];

                if (stream.ReadByte() != 0x00 || stream.Read(bytes, 0, bytes.Length) != bytes.Length)
                {
                    throw new InvalidDataException("Data does not conform to the Confluent wire format.");
                }

                if (BitConverter.IsLittleEndian)
                {
                    Array.Reverse(bytes);
                }

                var @delegate = await(_cache.GetOrAdd(BitConverter.ToInt32(bytes, 0), async id =>
                {
                    var json   = await RegistryClient.GetSchemaAsync(id).ConfigureAwait(false);
                    var schema = SchemaReader.Read(json);

                    return(DeserializerBuilder.BuildDelegate <T>(schema));
                })).ConfigureAwait(false);

                return(@delegate(stream));
            }
        }
        /// <summary>
        /// Builds a deserializer for the Confluent wire format.
        /// </summary>
        /// <param name="id">
        /// A schema ID that all payloads must be serialized with. If a received schema ID does not
        /// match this ID, <see cref="InvalidDataException" /> will be thrown.
        /// </param>
        /// <param name="json">
        /// The schema to build the Avro deserializer from.
        /// </param>
        /// <param name="tombstoneBehavior">
        /// The behavior of the deserializer on tombstone records.
        /// </param>
        protected virtual IDeserializer <T> Build <T>(
            int id,
            string json,
            TombstoneBehavior tombstoneBehavior
            )
        {
            var schema = SchemaReader.Read(json);

            if (tombstoneBehavior != TombstoneBehavior.None)
            {
                if (default(T) != null)
                {
                    throw new UnsupportedTypeException(typeof(T), $"{typeof(T)} cannot represent tombstone values.");
                }

                var hasNull = schema is NullSchema ||
                              (schema is UnionSchema union && union.Schemas.Any(s => s is NullSchema));

                if (tombstoneBehavior == TombstoneBehavior.Strict && hasNull)
                {
                    throw new UnsupportedSchemaException(schema, "Tombstone deserialization is not supported for schemas that can represent null values.");
                }
            }

            var deserialize = DeserializerBuilder.BuildDelegate <T>(schema);

            return(new DelegateDeserializer <T>((data, isNull, context) =>
            {
                if (isNull && tombstoneBehavior != TombstoneBehavior.None)
                {
                    if (context.Component == MessageComponentType.Value || tombstoneBehavior != TombstoneBehavior.Strict)
                    {
                        return default;
                    }
                }

                using (var stream = new MemoryStream(data, false))
                {
                    var bytes = new byte[4];

                    if (stream.ReadByte() != 0x00 || stream.Read(bytes, 0, bytes.Length) != bytes.Length)
                    {
                        throw new InvalidDataException("Data does not conform to the Confluent wire format.");
                    }

                    if (BitConverter.IsLittleEndian)
                    {
                        Array.Reverse(bytes);
                    }

                    var received = BitConverter.ToInt32(bytes, 0);

                    if (received != id)
                    {
                        throw new InvalidDataException($"The received schema ({received}) does not match the specified schema ({id}).");
                    }

                    return deserialize(stream);
                }
            }));
        }