Exemplo n.º 1
0
        private static void TypeInfoPropertiesDefaults_Generic <T>(JsonTypeInfo <T> ti)
        {
            if (ti.Kind == JsonTypeInfoKind.None)
            {
                Assert.Null(ti.CreateObject);
                Assert.Throws <InvalidOperationException>(() => ti.CreateObject = () => (T)Activator.CreateInstance(typeof(T)));
            }
            else
            {
                bool createObjCalled = false;
                Assert.NotNull(ti.CreateObject);
                Func <T> createObj = () =>
                {
                    createObjCalled = true;
                    return(default(T));
                };

                ti.CreateObject = createObj;
                Assert.Same(createObj, ti.CreateObject);

                JsonTypeInfo untyped = ti;
                if (typeof(T).IsValueType)
                {
                    Assert.NotSame(createObj, untyped.CreateObject);
                }
                else
                {
                    Assert.Same(createObj, untyped.CreateObject);
                }

                Assert.Same(untyped.CreateObject, untyped.CreateObject);
                Assert.Same(createObj, ti.CreateObject);
                untyped.CreateObject();
                Assert.True(createObjCalled);

                ti.CreateObject = null;
                Assert.Null(ti.CreateObject);
                Assert.Null(untyped.CreateObject);

                bool          untypedCreateObjCalled = false;
                Func <object> untypedCreateObj       = () =>
                {
                    untypedCreateObjCalled = true;
                    return(default(T));
                };
                untyped.CreateObject = untypedCreateObj;
                Assert.Same(untypedCreateObj, untyped.CreateObject);
                Assert.Same(ti.CreateObject, ti.CreateObject);
                Assert.NotSame(untypedCreateObj, ti.CreateObject);

                ti.CreateObject();
                Assert.True(untypedCreateObjCalled);

                untyped.CreateObject = null;
                Assert.Null(ti.CreateObject);
                Assert.Null(untyped.CreateObject);
            }
        }
        public static void ModifiersAreCalledAndModifyTypeInfos()
        {
            DefaultJsonTypeInfoResolver r     = new();
            JsonTypeInfo storedTypeInfo       = null;
            bool         createObjectCalled   = false;
            bool         secondModifierCalled = false;

            r.Modifiers.Add((ti) =>
            {
                Assert.Null(storedTypeInfo);
                storedTypeInfo = ti;

                // marker that test has modified something
                ti.CreateObject = () =>
                {
                    Assert.False(createObjectCalled);
                    createObjectCalled = true;

                    // we don't care what's returned as it won't be used by deserialization
                    return(null);
                };
            });

            r.Modifiers.Add((ti) =>
            {
                // this proves we've been called after first modifier
                Assert.NotNull(storedTypeInfo);
                Assert.Same(storedTypeInfo, ti);
                secondModifierCalled = true;
            });

            JsonTypeInfo returnedTypeInfo = r.GetTypeInfo(typeof(InvalidOperationException), new JsonSerializerOptions());

            Assert.NotNull(storedTypeInfo);
            Assert.Same(storedTypeInfo, returnedTypeInfo);

            Assert.False(createObjectCalled);
            // we call our previously set marker
            storedTypeInfo.CreateObject();

            Assert.True(createObjectCalled);
            Assert.True(secondModifierCalled);
        }
Exemplo n.º 3
0
        internal override bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options, ref ReadStack state, [MaybeNullWhen(false)] out T value)
        {
            JsonTypeInfo jsonTypeInfo = state.Current.JsonTypeInfo;

            object obj;

            if (!state.SupportContinuation && !state.Current.CanContainMetadata)
            {
                // Fast path that avoids maintaining state variables and dealing with preserved references.

                if (reader.TokenType != JsonTokenType.StartObject)
                {
                    ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(TypeToConvert);
                }

                if (jsonTypeInfo.CreateObject == null)
                {
                    ThrowHelper.ThrowNotSupportedException_DeserializeNoConstructor(jsonTypeInfo.Type, ref reader, ref state);
                }

                obj = jsonTypeInfo.CreateObject() !;

                jsonTypeInfo.OnDeserializing?.Invoke(obj);

                // Process all properties.
                while (true)
                {
                    // Read the property name or EndObject.
                    reader.ReadWithVerify();

                    JsonTokenType tokenType = reader.TokenType;

                    if (tokenType == JsonTokenType.EndObject)
                    {
                        break;
                    }

                    // Read method would have thrown if otherwise.
                    Debug.Assert(tokenType == JsonTokenType.PropertyName);

                    ReadOnlySpan <byte> unescapedPropertyName = JsonSerializer.GetPropertyName(ref state, ref reader, options);
                    JsonPropertyInfo    jsonPropertyInfo      = JsonSerializer.LookupProperty(
                        obj,
                        unescapedPropertyName,
                        ref state,
                        options,
                        out bool useExtensionProperty);

                    ReadPropertyValue(obj, ref state, ref reader, jsonPropertyInfo, useExtensionProperty);
                }
            }
            else
            {
                // Slower path that supports continuation and reading metadata.

                if (state.Current.ObjectState == StackFrameObjectState.None)
                {
                    if (reader.TokenType != JsonTokenType.StartObject)
                    {
                        ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(TypeToConvert);
                    }

                    state.Current.ObjectState = StackFrameObjectState.StartToken;
                }

                // Handle the metadata properties.
                if (state.Current.CanContainMetadata && state.Current.ObjectState < StackFrameObjectState.ReadMetadata)
                {
                    if (!JsonSerializer.TryReadMetadata(this, jsonTypeInfo, ref reader, ref state))
                    {
                        value = default;
                        return(false);
                    }

                    if (state.Current.MetadataPropertyNames == MetadataPropertyName.Ref)
                    {
                        value = JsonSerializer.ResolveReferenceId <T>(ref state);
                        return(true);
                    }

                    state.Current.ObjectState = StackFrameObjectState.ReadMetadata;
                }

                // Dispatch to any polymorphic converters: should always be entered regardless of ObjectState progress
                if (state.Current.MetadataPropertyNames.HasFlag(MetadataPropertyName.Type) &&
                    state.Current.PolymorphicSerializationState != PolymorphicSerializationState.PolymorphicReEntryStarted &&
                    ResolvePolymorphicConverter(jsonTypeInfo, options, ref state) is JsonConverter polymorphicConverter)
                {
                    Debug.Assert(!IsValueType);
                    bool success = polymorphicConverter.OnTryReadAsObject(ref reader, options, ref state, out object?objectResult);
                    value = (T)objectResult !;
                    state.ExitPolymorphicConverter(success);
                    return(success);
                }

                if (state.Current.ObjectState < StackFrameObjectState.CreatedObject)
                {
                    if (state.Current.CanContainMetadata)
                    {
                        JsonSerializer.ValidateMetadataForObjectConverter(this, ref reader, ref state);
                    }

                    if (state.Current.MetadataPropertyNames == MetadataPropertyName.Ref)
                    {
                        value = JsonSerializer.ResolveReferenceId <T>(ref state);
                        return(true);
                    }

                    if (jsonTypeInfo.CreateObject == null)
                    {
                        ThrowHelper.ThrowNotSupportedException_DeserializeNoConstructor(jsonTypeInfo.Type, ref reader, ref state);
                    }

                    obj = jsonTypeInfo.CreateObject() !;

                    if (state.Current.MetadataPropertyNames.HasFlag(MetadataPropertyName.Id))
                    {
                        Debug.Assert(state.ReferenceId != null);
                        Debug.Assert(options.ReferenceHandlingStrategy == ReferenceHandlingStrategy.Preserve);
                        state.ReferenceResolver.AddReference(state.ReferenceId, obj);
                        state.ReferenceId = null;
                    }

                    jsonTypeInfo.OnDeserializing?.Invoke(obj);

                    state.Current.ReturnValue = obj;
                    state.Current.ObjectState = StackFrameObjectState.CreatedObject;
                }
                else
                {
                    obj = state.Current.ReturnValue !;
                    Debug.Assert(obj != null);
                }

                // Process all properties.
                while (true)
                {
                    // Determine the property.
                    if (state.Current.PropertyState == StackFramePropertyState.None)
                    {
                        state.Current.PropertyState = StackFramePropertyState.ReadName;

                        if (!reader.Read())
                        {
                            // The read-ahead functionality will do the Read().
                            state.Current.ReturnValue = obj;
                            value = default;
                            return(false);
                        }
                    }

                    JsonPropertyInfo jsonPropertyInfo;

                    if (state.Current.PropertyState < StackFramePropertyState.Name)
                    {
                        state.Current.PropertyState = StackFramePropertyState.Name;

                        JsonTokenType tokenType = reader.TokenType;
                        if (tokenType == JsonTokenType.EndObject)
                        {
                            break;
                        }

                        // Read method would have thrown if otherwise.
                        Debug.Assert(tokenType == JsonTokenType.PropertyName);

                        ReadOnlySpan <byte> unescapedPropertyName = JsonSerializer.GetPropertyName(ref state, ref reader, options);
                        jsonPropertyInfo = JsonSerializer.LookupProperty(
                            obj,
                            unescapedPropertyName,
                            ref state,
                            options,
                            out bool useExtensionProperty);

                        state.Current.UseExtensionProperty = useExtensionProperty;
                    }
                    else
                    {
                        Debug.Assert(state.Current.JsonPropertyInfo != null);
                        jsonPropertyInfo = state.Current.JsonPropertyInfo !;
                    }

                    if (state.Current.PropertyState < StackFramePropertyState.ReadValue)
                    {
                        if (!jsonPropertyInfo.CanDeserialize)
                        {
                            if (!reader.TrySkip())
                            {
                                state.Current.ReturnValue = obj;
                                value = default;
                                return(false);
                            }

                            state.Current.EndProperty();
                            continue;
                        }

                        if (!ReadAheadPropertyValue(ref state, ref reader, jsonPropertyInfo))
                        {
                            state.Current.ReturnValue = obj;
                            value = default;
                            return(false);
                        }
                    }

                    if (state.Current.PropertyState < StackFramePropertyState.TryRead)
                    {
                        // Obtain the CLR value from the JSON and set the member.
                        if (!state.Current.UseExtensionProperty)
                        {
                            if (!jsonPropertyInfo.ReadJsonAndSetMember(obj, ref state, ref reader))
                            {
                                state.Current.ReturnValue = obj;
                                value = default;
                                return(false);
                            }
                        }
                        else
                        {
                            if (!jsonPropertyInfo.ReadJsonAndAddExtensionProperty(obj, ref state, ref reader))
                            {
                                // No need to set 'value' here since JsonElement must be read in full.
                                state.Current.ReturnValue = obj;
                                value = default;
                                return(false);
                            }
                        }

                        state.Current.EndProperty();
                    }
                }
            }

            jsonTypeInfo.OnDeserialized?.Invoke(obj);

            // Unbox
            Debug.Assert(obj != null);
            value = (T)obj;

            // Check if we are trying to build the sorted cache.
            if (state.Current.PropertyRefCache != null)
            {
                jsonTypeInfo.UpdateSortedPropertyCache(ref state.Current);
            }

            return(true);
        }