示例#1
0
        internal sealed override bool OnTryWrite(
            Utf8JsonWriter writer,
            T value,
            JsonSerializerOptions options,
            ref WriteStack state)
        {
            JsonTypeInfo jsonTypeInfo = state.Current.JsonTypeInfo;

            object obj = value; // box once

            if (!state.SupportContinuation)
            {
                writer.WriteStartObject();
                if (options.ReferenceHandlingStrategy == ReferenceHandlingStrategy.Preserve)
                {
                    if (JsonSerializer.WriteReferenceForObject(this, obj, ref state, writer) == MetadataPropertyName.Ref)
                    {
                        return(true);
                    }
                }

                if (obj is IJsonOnSerializing onSerializing)
                {
                    onSerializing.OnSerializing();
                }

                List <KeyValuePair <string, JsonPropertyInfo?> > properties = jsonTypeInfo.PropertyCache !.List;
                for (int i = 0; i < properties.Count; i++)
                {
                    JsonPropertyInfo jsonPropertyInfo = properties[i].Value !;
                    if (jsonPropertyInfo.ShouldSerialize)
                    {
                        // Remember the current property for JsonPath support if an exception is thrown.
                        state.Current.DeclaredJsonPropertyInfo = jsonPropertyInfo;
                        state.Current.NumberHandling           = jsonPropertyInfo.NumberHandling;

                        bool success = jsonPropertyInfo.GetMemberAndWriteJson(obj, ref state, writer);
                        // Converters only return 'false' when out of data which is not possible in fast path.
                        Debug.Assert(success);

                        state.Current.EndProperty();
                    }
                }

                // Write extension data after the normal properties.
                JsonPropertyInfo?dataExtensionProperty = jsonTypeInfo.DataExtensionProperty;
                if (dataExtensionProperty?.ShouldSerialize == true)
                {
                    // Remember the current property for JsonPath support if an exception is thrown.
                    state.Current.DeclaredJsonPropertyInfo = dataExtensionProperty;
                    state.Current.NumberHandling           = dataExtensionProperty.NumberHandling;

                    bool success = dataExtensionProperty.GetMemberAndWriteJsonExtensionData(obj, ref state, writer);
                    Debug.Assert(success);

                    state.Current.EndProperty();
                }

                writer.WriteEndObject();
            }
            else
            {
                if (!state.Current.ProcessedStartToken)
                {
                    writer.WriteStartObject();
                    if (options.ReferenceHandlingStrategy == ReferenceHandlingStrategy.Preserve)
                    {
                        if (JsonSerializer.WriteReferenceForObject(this, obj, ref state, writer) == MetadataPropertyName.Ref)
                        {
                            return(true);
                        }
                    }

                    if (obj is IJsonOnSerializing onSerializing)
                    {
                        onSerializing.OnSerializing();
                    }

                    state.Current.ProcessedStartToken = true;
                }

                List <KeyValuePair <string, JsonPropertyInfo?> >?propertyList = jsonTypeInfo.PropertyCache !.List !;
                while (state.Current.EnumeratorIndex < propertyList.Count)
                {
                    JsonPropertyInfo?jsonPropertyInfo = propertyList ![state.Current.EnumeratorIndex].Value;
示例#2
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.UseFastPath)
            {
                // 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 !() !;

                if (obj is IJsonOnDeserializing onDeserializing)
                {
                    onDeserializing.OnDeserializing();
                }

                // 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 preserved references.

                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.ObjectState < StackFrameObjectState.PropertyValue)
                {
                    if (options.ReferenceHandlingStrategy == ReferenceHandlingStrategy.Preserve)
                    {
                        if (JsonSerializer.ResolveMetadataForJsonObject <T>(ref reader, ref state, options))
                        {
                            if (state.Current.ObjectState == StackFrameObjectState.ReadRefEndObject)
                            {
                                // This will never throw since it was previously validated in ResolveMetadataForJsonObject.
                                value = (T)state.Current.ReturnValue !;
                                return(true);
                            }
                        }
                        else
                        {
                            value = default;
                            return(false);
                        }
                    }
                }

                if (state.Current.ObjectState < StackFrameObjectState.CreatedObject)
                {
                    if (jsonTypeInfo.CreateObject == null)
                    {
                        ThrowHelper.ThrowNotSupportedException_DeserializeNoConstructor(jsonTypeInfo.Type, ref reader, ref state);
                    }

                    obj = jsonTypeInfo.CreateObject !() !;

                    if (obj is IJsonOnDeserializing onDeserializing)
                    {
                        onDeserializing.OnDeserializing();
                    }

                    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.ShouldDeserialize)
                        {
                            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();
                    }
                }
            }

            if (obj is IJsonOnDeserialized onDeserialized)
            {
                onDeserialized.OnDeserialized();
            }

            // 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);
        }
示例#3
0
 public PropertyRef(ulong key, JsonPropertyInfo info)
 {
     Key  = key;
     Info = info;
 }
示例#4
0
        internal override bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options, ref ReadStack state, [MaybeNullWhen(false)] out T value)
        {
            bool   shouldReadPreservedReferences = options.ReferenceHandling.ShouldReadPreservedReferences();
            object obj;

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

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

                if (state.Current.JsonClassInfo.CreateObject == null)
                {
                    ThrowHelper.ThrowNotSupportedException_DeserializeNoParameterlessConstructor(state.Current.JsonClassInfo.Type);
                }

                obj = state.Current.JsonClassInfo.CreateObject !() !;

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

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

                    if (tokenType != JsonTokenType.PropertyName)
                    {
                        ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(TypeToConvert);
                    }

                    JsonPropertyInfo jsonPropertyInfo = JsonSerializer.LookupProperty(
                        obj,
                        ref reader,
                        options,
                        ref state,
                        out bool useExtensionProperty);

                    // Skip the property if not found.
                    if (!jsonPropertyInfo.ShouldDeserialize)
                    {
                        reader.Skip();
                        state.Current.EndProperty();
                        continue;
                    }

                    // Set the property value.
                    reader.ReadWithVerify();

                    if (!useExtensionProperty)
                    {
                        jsonPropertyInfo.ReadJsonAndSetMember(obj, ref state, ref reader);
                    }
                    else
                    {
                        jsonPropertyInfo.ReadJsonAndAddExtensionProperty(obj, ref state, ref reader);
                    }

                    // Ensure any exception thrown in the next read does not have a property in its JsonPath.
                    state.Current.EndProperty();
                }
            }
            else
            {
                // Slower path that supports continuation and preserved references.

                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.ObjectState < StackFrameObjectState.MetadataPropertyValue)
                {
                    if (shouldReadPreservedReferences)
                    {
                        if (JsonSerializer.ResolveMetadata(this, ref reader, ref state))
                        {
                            if (state.Current.ObjectState == StackFrameObjectState.MetadataRefPropertyEndObject)
                            {
                                value = (T)state.Current.ReturnValue !;
                                return(true);
                            }
                        }
                        else
                        {
                            value = default !;
        internal sealed override bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options, ref ReadStack state, [MaybeNullWhen(false)] out T value)
        {
            object        obj;
            ArgumentState argumentState = state.Current.CtorArgumentState !;

            if (state.UseFastPath)
            {
                // Fast path that avoids maintaining state variables.

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

                ReadOnlySpan <byte> originalSpan = reader.OriginalSpan;

                ReadConstructorArguments(ref state, ref reader, options);

                obj = (T)CreateObject(ref state.Current);

                if (obj is IJsonOnDeserializing onDeserializing)
                {
                    onDeserializing.OnDeserializing();
                }

                if (argumentState.FoundPropertyCount > 0)
                {
                    Utf8JsonReader tempReader;

                    FoundProperty[]? properties = argumentState.FoundProperties;
                    Debug.Assert(properties != null);

                    for (int i = 0; i < argumentState.FoundPropertyCount; i++)
                    {
                        JsonPropertyInfo jsonPropertyInfo    = properties[i].Item1;
                        long             resumptionByteIndex = properties[i].Item3;
                        byte[]? propertyNameArray = properties[i].Item4;
                        string?dataExtKey = properties[i].Item5;

                        tempReader = new Utf8JsonReader(
                            originalSpan.Slice(checked ((int)resumptionByteIndex)),
                            isFinalBlock: true,
                            state: properties[i].Item2);

                        Debug.Assert(tempReader.TokenType == JsonTokenType.PropertyName);

                        state.Current.JsonPropertyName = propertyNameArray;
                        state.Current.JsonPropertyInfo = jsonPropertyInfo;
                        state.Current.NumberHandling   = jsonPropertyInfo.NumberHandling;

                        bool useExtensionProperty = dataExtKey != null;

                        if (useExtensionProperty)
                        {
                            Debug.Assert(jsonPropertyInfo == state.Current.JsonTypeInfo.DataExtensionProperty);
                            state.Current.JsonPropertyNameAsString = dataExtKey;
                            JsonSerializer.CreateDataExtensionProperty(obj, jsonPropertyInfo, options);
                        }

                        ReadPropertyValue(obj, ref state, ref tempReader, jsonPropertyInfo, useExtensionProperty);
                    }

                    FoundProperty[] toReturn = argumentState.FoundProperties !;
                    argumentState.FoundProperties = null;
                    ArrayPool <FoundProperty> .Shared.Return(toReturn, clearArray: true);
                }
            }
            else
            {
                // Slower path that supports continuation and metadata reads.

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

                    state.Current.ObjectState = StackFrameObjectState.StartToken;
                }

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

                    state.Current.ObjectState = StackFrameObjectState.ReadMetadata;
                }

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

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

                    BeginRead(ref state, ref reader, options);

                    state.Current.ObjectState = StackFrameObjectState.ConstructorArguments;
                }

                if (!ReadConstructorArgumentsWithContinuation(ref state, ref reader, options))
                {
                    value = default;
                    return(false);
                }

                obj = (T)CreateObject(ref state.Current);

                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;
                }

                if (obj is IJsonOnDeserializing onDeserializing)
                {
                    onDeserializing.OnDeserializing();
                }

                if (argumentState.FoundPropertyCount > 0)
                {
                    for (int i = 0; i < argumentState.FoundPropertyCount; i++)
                    {
                        JsonPropertyInfo jsonPropertyInfo = argumentState.FoundPropertiesAsync ![i].Item1;
示例#6
0
        public static void CombineCustomResolverWithDefault()
        {
            TestResolver resolver = new TestResolver((Type type, JsonSerializerOptions options) =>
            {
                if (type != typeof(TestClass))
                {
                    return(null);
                }

                JsonTypeInfo <TestClass> ti = JsonTypeInfo.CreateJsonTypeInfo <TestClass>(options);
                ti.CreateObject             = () => new TestClass()
                {
                    TestField    = string.Empty,
                    TestProperty = 42,
                };

                JsonPropertyInfo field = ti.CreateJsonPropertyInfo(typeof(string), "MyTestField");
                field.Get = (o) =>
                {
                    TestClass obj = (TestClass)o;
                    return(obj.TestField ?? string.Empty);
                };

                field.Set = (o, val) =>
                {
                    TestClass obj = (TestClass)o;
                    string value  = (string?)val ?? string.Empty;
                    obj.TestField = value;
                };

                field.ShouldSerialize = (o, val) => (string)val != string.Empty;

                JsonPropertyInfo prop = ti.CreateJsonPropertyInfo(typeof(int), "MyTestProperty");
                prop.Get = (o) =>
                {
                    TestClass obj = (TestClass)o;
                    return(obj.TestProperty);
                };

                prop.Set = (o, val) =>
                {
                    TestClass obj    = (TestClass)o;
                    obj.TestProperty = (int)val;
                };

                prop.ShouldSerialize = (o, val) => (int)val != 42;

                ti.Properties.Add(field);
                ti.Properties.Add(prop);
                return(ti);
            });

            JsonSerializerOptions options = new JsonSerializerOptions();

            options.IncludeFields    = true;
            options.TypeInfoResolver = JsonTypeInfoResolver.Combine(resolver, options.TypeInfoResolver);

            TestClass originalObj = new TestClass()
            {
                TestField    = "test value",
                TestProperty = 45,
            };

            string json = JsonSerializer.Serialize(originalObj, options);

            Assert.Equal(@"{""MyTestField"":""test value"",""MyTestProperty"":45}", json);

            TestClass deserialized = JsonSerializer.Deserialize <TestClass>(json, options);

            Assert.Equal(originalObj.TestField, deserialized.TestField);
            Assert.Equal(originalObj.TestProperty, deserialized.TestProperty);

            originalObj.TestField = null;
            json = JsonSerializer.Serialize(originalObj, options);
            Assert.Equal(@"{""MyTestProperty"":45}", json);

            originalObj.TestField = string.Empty;
            json = JsonSerializer.Serialize(originalObj, options);
            Assert.Equal(@"{""MyTestProperty"":45}", json);

            deserialized = JsonSerializer.Deserialize <TestClass>(json, options);
            Assert.Equal(originalObj.TestField, deserialized.TestField);
            Assert.Equal(originalObj.TestProperty, deserialized.TestProperty);

            originalObj.TestField    = "test value";
            originalObj.TestProperty = 42;
            json = JsonSerializer.Serialize(originalObj, options);
            Assert.Equal(@"{""MyTestField"":""test value""}", json);
            deserialized = JsonSerializer.Deserialize <TestClass>(json, options);
            Assert.Equal(originalObj.TestField, deserialized.TestField);
            Assert.Equal(originalObj.TestProperty, deserialized.TestProperty);
        }