Esempio n. 1
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);
                }
            }
        }
Esempio n. 2
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;
            });
        }