Пример #1
0
        private static void SkipAsArray(JsonReader reader)
        {
            var part      = new BufferPart();
            var firstPass = true;

            while (true)
            {
                var token = reader.Read(ref part, out var _);
                if (token == JsonToken.ArrayEnd && firstPass)
                {
                    return;
                }
                SkipFromCurrent(reader, token);
                token = reader.Read(ref part, out var _);
                if (token == JsonToken.ArrayEnd)
                {
                    return;
                }
                if (token != JsonToken.ValueSeparator)
                {
                    throw Exceptions.BadToken(reader, token, JsonToken.ValueSeparator);
                }
                firstPass = false;
            }
        }
Пример #2
0
        private static Func <DeserializationContext, object> ForEnum(Type type, Func <Type, TypeDescriptor> descriptorSource)
        {
            var underlyingType = Enum.GetUnderlyingType(type);
            var descriptor     = descriptorSource(underlyingType);
            var enumValues     = new Dictionary <string, object>();
            var toUnderlying   = ReflectionUtils.BuildCaster(underlyingType);

            foreach (var value in Enum.GetValues(type))
            {
                enumValues[value.ToString()] = value;
                enumValues[toUnderlying(value).ToString()] = value;
            }

            return(context =>
            {
                var reader = context.Reader;
                if (reader.PeekToken().HasFlag(JsonToken.Number))
                {
                    return Enum.ToObject(type, descriptor.Reader(context));
                }

                var bufferPart = new BufferPart();
                var token = reader.Read(ref bufferPart, out var text);
                if (token != JsonToken.String)
                {
                    throw Exceptions.BadToken(reader, token, JsonToken.String | JsonToken.Number);
                }

                return enumValues.TryGetValue(text, out var value)
                                        ? value
                                        : throw new JsonException($"Unknown enum value '{text}' near line {reader.Line}, column {reader.Column}.");
            });
        }
Пример #3
0
        private static void SkipAsObject(JsonReader reader)
        {
            var part      = new BufferPart();
            var firstPass = true;

            while (true)
            {
                var token = reader.Read(ref part, out var _);
                if (token == JsonToken.ObjectEnd && firstPass)
                {
                    return;
                }
                if (token != JsonToken.String)
                {
                    throw Exceptions.BadToken(reader, token, JsonToken.String);
                }

                AssertToken(JsonToken.NameSeparator, reader, ref part);
                SkipNext(reader);
                token = reader.Read(ref part, out var _);
                if (token == JsonToken.ObjectEnd)
                {
                    return;
                }
                if (token != JsonToken.ValueSeparator)
                {
                    throw Exceptions.BadToken(reader, token, JsonToken.ValueSeparator);
                }
                firstPass = false;
            }
        }
Пример #4
0
        private static void AssertToken(JsonToken expected, JsonReader reader, ref BufferPart buffer)
        {
            var token = reader.Read(ref buffer, out var _);

            if (!token.HasFlag(expected))
            {
                throw Exceptions.BadToken(reader, token, expected);
            }
        }
Пример #5
0
        private static Func <DeserializationContext, object> ForCollection(Type type, Func <Type, TypeDescriptor> descriptorSource)
        {
            var element           = ReflectionUtils.FindCollectionElementType(type);
            var constructor       = ReflectionUtils.BuildConstructor(typeof(List <>).MakeGenericType(element));
            var elementDescriptor = descriptorSource(element);

            return(context =>
            {
                var reader = context.Reader;
                var bufferPart = new BufferPart();
                var token = reader.Read(ref bufferPart, out var _);
                if (token == JsonToken.Null)
                {
                    return null;
                }
                var target = (IList)constructor();
                if (token != JsonToken.ArrayStart)
                {
                    throw Exceptions.BadToken(reader, token, JsonToken.ObjectStart);
                }

                var finalizer = type.IsArray
                                        ? new Func <IList, object>(i =>
                {
                    var array = Array.CreateInstance(element, i.Count);
                    i.CopyTo(array, 0);
                    return array;
                })
                                        : null;

                var isFirst = true;
                while (true)
                {
                    if (reader.PeekToken() == JsonToken.ArrayEnd)
                    {
                        reader.Read(ref bufferPart, out var _);
                        return finalizer != null?finalizer(target) : target;
                    }
                    if (!isFirst)
                    {
                        token = reader.Read(ref bufferPart, out var _);
                        if (token != JsonToken.ValueSeparator)
                        {
                            throw Exceptions.BadToken(reader, token, JsonToken.ValueSeparator);
                        }
                    }

                    var item = elementDescriptor.Reader(context);
                    target.Add(item);

                    isFirst = false;
                }
            });
        }
Пример #6
0
        private static void SkipFromCurrent(JsonReader reader, JsonToken current)
        {
            if (AtomicTokens.HasFlag(current))
            {
                return;
            }

            switch (current)
            {
            case JsonToken.ArrayStart: SkipAsArray(reader); return;

            case JsonToken.ObjectStart: SkipAsObject(reader); return;
            }

            throw Exceptions.BadToken(reader, current, JsonToken.ArrayStart | JsonToken.ObjectStart);
        }
Пример #7
0
        public static bool ReadBool(JsonReader reader)
        {
            var part  = new BufferPart();
            var token = reader.Read(ref part, out var buffer);

            if (token == JsonToken.True)
            {
                return(true);
            }
            if (token == JsonToken.False)
            {
                return(false);
            }
            if (token.HasFlag(JsonToken.Number))
            {
                if (part.Length == 1)
                {
                    return(part.Text[part.Start] != '0');
                }
                var text = part.Text.Substring(part.Start, part.Length);
                if (token.HasFlag(JsonToken.NumberFloat))
                {
                    return(double.TryParse(text, Base10WithExponent, CultureInfo.InvariantCulture, out var value)
                                                ? value != 0
                                                : throw Exceptions.BadFormat(reader, "double value"));
                }
                return(long.TryParse(text, out var result) ? result != 0 : throw Exceptions.BadFormat(reader, "numeric value"));
            }
            if (token == JsonToken.String)
            {
                try
                {
                    return(Convert.ToBoolean(buffer, CultureInfo.InvariantCulture));
                }
                catch (FormatException)
                {
                    throw Exceptions.BadFormat(reader, "bool value");
                }
            }

            throw Exceptions.BadToken(reader, token, JsonToken.False | JsonToken.True);
        }
Пример #8
0
        private static Func <DeserializationContext, object> ForNullable(Type underlyingType, Func <Type, TypeDescriptor> descriptorSource)
        {
            var descriptor = descriptorSource(underlyingType);

            return(context =>
            {
                var reader = context.Reader;
                if (reader.PeekToken() != JsonToken.Null)
                {
                    return descriptor.Reader(context);
                }

                var bufferPart = new BufferPart();
                var token = reader.Read(ref bufferPart, out var _);
                if (token != JsonToken.Null)
                {
                    throw Exceptions.BadToken(reader, token, JsonToken.Null);
                }

                return null;
            });
        }
Пример #9
0
        public static int ReadInt(JsonReader reader)
        {
            var part  = new BufferPart();
            var token = reader.Read(ref part, out var buffer);
            int value;

            if (token == JsonToken.String)
            {
                return(int.TryParse(buffer, out value) ? value : throw Exceptions.BadFormat(reader, "integer value"));
            }

            if (!token.HasFlag(JsonToken.Number))
            {
                throw Exceptions.BadToken(reader, token, JsonToken.Number);
            }
            if (token.HasFlag(JsonToken.NumberFloat) || token.HasFlag(JsonToken.NumberExponent))
            {
                throw Exceptions.BadFormat(reader, "integer value");
            }

            return(Parsing.TryParseBase10Int(part.Text, part.Start, part.Length, out value)
                                ? value
                                : throw Exceptions.BadFormat(reader, "integer value"));
        }
Пример #10
0
        private static IEnumerable <DeferredEntry> ReadProperties(object target, DeserializationContext context, IReadOnlyDictionary <string, PropertyBinding> all)
        {
            var bufferPart = new BufferPart();
            var reader     = context.Reader;
            List <DeferredEntry> deferred = null;

            while (true)
            {
                var token = reader.Read(ref bufferPart, out var propertyName);
                if (token == JsonToken.ObjectEnd)
                {
                    return(deferred);
                }
                if (token != JsonToken.String)
                {
                    throw Exceptions.BadToken(reader, token, JsonToken.String);
                }

                var hasProperty = all.TryGetValue(propertyName, out var property);
                token = reader.Read(ref bufferPart, out var _);
                if (token != JsonToken.NameSeparator)
                {
                    throw Exceptions.BadToken(reader, token, JsonToken.NameSeparator);
                }

                if (hasProperty)
                {
                    ITypeSelector typeSelector = null;
                    var           shouldDeffer = context.TypeSelectors?.TryGetValue(property.Descriptor.Type, out typeSelector) == true;
                    if (!shouldDeffer)
                    {
                        property.Setter(target, property.Descriptor.Reader(context));
                    }
                    else
                    {
                        var entry = new DeferredEntry
                        {
                            Selector = typeSelector,
                            Binding  = property,
                            Snapshot = reader.TakeSnapshot()
                        };
                        ValueSkipper.SkipNext(reader);
                        if (deferred == null)
                        {
                            deferred = new List <DeferredEntry>();
                        }
                        deferred.Add(entry);
                    }
                }
                else
                {
                    ValueSkipper.SkipNext(reader);
                }

                token = reader.Read(ref bufferPart, out var _);
                if (token == JsonToken.ObjectEnd)
                {
                    return(deferred);
                }
                if (token != JsonToken.ValueSeparator)
                {
                    throw Exceptions.BadToken(reader, token, JsonToken.ValueSeparator);
                }
            }
        }
Пример #11
0
        private static Func <DeserializationContext, object> ForComplex(Type type, TypeOptions options, Func <Type, TypeDescriptor> descriptorSource)
        {
            var info = type.GetTypeInfo();

            if (info.IsClass && info.GetConstructor(Type.EmptyTypes) == null)
            {
                return(reader => throw new JsonException(info.IsAbstract
                                        ? $"Type {type} is abstract. Add {nameof(ITypeSelector)} to {nameof(SerializationSettings)} in order to deserialize this type."
                                        : $"Type {type} must define public parameterless constructor."));
            }

            var properties = info
                             .GetProperties(BindingFlags.Instance | BindingFlags.Public)
                             .Where(i => i.SetMethod != null && i.GetMethod != null)
                             .Select(i => new { Property = (MemberInfo)i, Setter = ReflectionUtils.BuildSetter(i), Descriptor = descriptorSource(i.PropertyType) });

            var fields = info
                         .GetFields(BindingFlags.Instance | BindingFlags.Public)
                         .Select(i => new { Property = (MemberInfo)i, Setter = ReflectionUtils.BuildFieldSetter(i), Descriptor = descriptorSource(i.FieldType) });

            var all = properties
                      .Concat(fields)
                      .SelectMany(i => JsonNames(i.Property).Select(j => new PropertyBinding {
                Name = j, Setter = i.Setter, Descriptor = i.Descriptor
            }))
                      .GroupBy(i => i.Name)
                      .ToDictionary(i => i.Key, i => i.First());

            var constructor = info.IsClass
                                ? ReflectionUtils.BuildConstructor(type)
                                : () => Activator.CreateInstance(typeof(Box <>).MakeGenericType(type));

            //struct types are internally wrapped into Box<T> type (see ReflectionUtils)
            var unwrapper = !info.IsClass
                                ? new Func <object, object>(i => ((IBox)i).Value)
                                : null;

            return(context =>
            {
                var bufferPart = new BufferPart();
                var reader = context.Reader;
                var token = reader.Read(ref bufferPart, out var _);
                if (token == JsonToken.Null)
                {
                    return info.IsClass ? (object)null : throw new JsonException($"Unable to assign null value to struct type near line {reader.Line}, column {reader.Column}.");
                }
                if (token != JsonToken.ObjectStart)
                {
                    throw Exceptions.BadToken(reader, token, JsonToken.ObjectStart);
                }
                var target = constructor();
                var deferred = ReadProperties(target, context, all);
                var unwrapped = unwrapper != null?unwrapper(target) : target;

                if (deferred == null)
                {
                    return unwrapped;
                }

                foreach (var entry in deferred)
                {
                    var runtimeType = entry.Selector.FindPropertyType(entry.Binding.Name, unwrapped);
                    var descriptor = context.Catalog.GetDescriptor(runtimeType, options);
                    using (reader.LoadSnapshot(entry.Snapshot))
                        entry.Binding.Setter(target, descriptor.Reader(context));
                }
                return unwrapper != null?unwrapper(target) : target;
            });
        }