From cd35514b600466314940c29b02d59bbc446e4341 Mon Sep 17 00:00:00 2001 From: Layomi Akinrinade Date: Sun, 18 Apr 2021 22:24:37 -0700 Subject: [PATCH 1/2] Add new methods to JsonSerializer and System.Net.Http.Json APIs that take type metadata --- .../ref/System.Net.Http.Json.cs | 6 + .../Http/Json/HttpClientJsonExtensions.Get.cs | 64 ++++++ .../Http/Json/HttpContentJsonExtensions.cs | 61 ++++- .../HttpClientJsonExtensionsTests.cs | 33 ++- .../FunctionalTests/JsonContext/Int32.cs | 33 +++ .../JsonContext/JsonContext.cs | 60 +++++ .../FunctionalTests/JsonContext/Person.cs | 103 +++++++++ .../FunctionalTests/JsonContext/String.cs | 33 +++ ...stem.Net.Http.Json.Functional.Tests.csproj | 31 ++- .../System.Text.Json/ref/System.Text.Json.cs | 208 ++++++++++-------- .../src/System/Text/Json/JsonHelpers.cs | 2 +- .../Serialization/JsonSerializer.Read.Span.cs | 82 +++++++ .../JsonSerializer.Read.Stream.cs | 112 +++++++++- .../JsonSerializer.Read.String.cs | 94 +++++++- .../JsonSerializer.Read.Utf8JsonReader.cs | 125 +++++++++++ .../JsonSerializer.Write.ByteArray.cs | 78 +++++-- .../JsonSerializer.Write.Helpers.cs | 83 ++++--- .../JsonSerializer.Write.Stream.cs | 119 ++++++++-- .../JsonSerializer.Write.String.cs | 86 +++----- .../JsonSerializer.Write.Utf8JsonWriter.cs | 81 +++++-- .../Serialization/JsonSerializerOptions.cs | 2 +- .../Metadata/JsonTypeInfo.Cache.cs | 7 +- .../Text/Json/Serialization/WriteStack.cs | 6 +- .../Text/Json/ThrowHelper.Serialization.cs | 2 +- .../Serialization/DeserializationWrapper.cs | 78 ++++++- .../JsonContext/DateTimeOffset.cs | 33 +++ .../MetadataTests/JsonContext/Dictionary.cs | 34 +++ .../MetadataTests/JsonContext/HighLowTemps.cs | 77 +++++++ .../MetadataTests/JsonContext/Int32.cs | 33 +++ .../JsonContext.GetJsonTypeInfo.cs | 21 ++ .../MetadataTests/JsonContext/JsonContext.cs | 48 ++++ .../MetadataTests/JsonContext/List.cs | 34 +++ .../MetadataTests/JsonContext/String.cs | 33 +++ .../MetadataTests/JsonContext/StringArray.cs | 33 +++ .../JsonContext/WeatherForecastWithPOCOs.cs | 142 ++++++++++++ .../MetadataTests.JsonMetadataServices.cs} | 18 +- .../MetadataTests.JsonSerializer.cs | 86 ++++++++ .../MetadataTests.Options.cs} | 12 +- .../MetadataTests/MetadataTests.cs | 58 +++++ .../Serialization/SerializationWrapper.cs | 57 +++++ .../System.Text.Json.Tests.csproj | 16 +- 41 files changed, 2004 insertions(+), 320 deletions(-) create mode 100644 src/libraries/System.Net.Http.Json/tests/FunctionalTests/JsonContext/Int32.cs create mode 100644 src/libraries/System.Net.Http.Json/tests/FunctionalTests/JsonContext/JsonContext.cs create mode 100644 src/libraries/System.Net.Http.Json/tests/FunctionalTests/JsonContext/Person.cs create mode 100644 src/libraries/System.Net.Http.Json/tests/FunctionalTests/JsonContext/String.cs create mode 100644 src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/DateTimeOffset.cs create mode 100644 src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/Dictionary.cs create mode 100644 src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/HighLowTemps.cs create mode 100644 src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/Int32.cs create mode 100644 src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/JsonContext.GetJsonTypeInfo.cs create mode 100644 src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/JsonContext.cs create mode 100644 src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/List.cs create mode 100644 src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/String.cs create mode 100644 src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/StringArray.cs create mode 100644 src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/WeatherForecastWithPOCOs.cs rename src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/{MetadataServicesTests/MetadataServicesTests.cs => MetadataTests/MetadataTests.JsonMetadataServices.cs} (96%) create mode 100644 src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/MetadataTests.JsonSerializer.cs rename src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/{MetadataServicesTests/MetadataServicesTests.Options.cs => MetadataTests/MetadataTests.Options.cs} (92%) create mode 100644 src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/MetadataTests.cs diff --git a/src/libraries/System.Net.Http.Json/ref/System.Net.Http.Json.cs b/src/libraries/System.Net.Http.Json/ref/System.Net.Http.Json.cs index 34e35f7883399..0010ea20d123a 100644 --- a/src/libraries/System.Net.Http.Json/ref/System.Net.Http.Json.cs +++ b/src/libraries/System.Net.Http.Json/ref/System.Net.Http.Json.cs @@ -9,12 +9,16 @@ namespace System.Net.Http.Json public static partial class HttpClientJsonExtensions { public static System.Threading.Tasks.Task GetFromJsonAsync(this System.Net.Http.HttpClient client, string? requestUri, System.Type type, System.Text.Json.JsonSerializerOptions? options, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public static System.Threading.Tasks.Task GetFromJsonAsync(this System.Net.Http.HttpClient client, string? requestUri, System.Type type, System.Text.Json.Serialization.JsonSerializerContext context, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public static System.Threading.Tasks.Task GetFromJsonAsync(this System.Net.Http.HttpClient client, string? requestUri, System.Type type, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public static System.Threading.Tasks.Task GetFromJsonAsync(this System.Net.Http.HttpClient client, System.Uri? requestUri, System.Type type, System.Text.Json.JsonSerializerOptions? options, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public static System.Threading.Tasks.Task GetFromJsonAsync(this System.Net.Http.HttpClient client, System.Uri? requestUri, System.Type type, System.Text.Json.Serialization.JsonSerializerContext context, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public static System.Threading.Tasks.Task GetFromJsonAsync(this System.Net.Http.HttpClient client, System.Uri? requestUri, System.Type type, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public static System.Threading.Tasks.Task GetFromJsonAsync(this System.Net.Http.HttpClient client, string? requestUri, System.Text.Json.JsonSerializerOptions? options, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public static System.Threading.Tasks.Task GetFromJsonAsync(this System.Net.Http.HttpClient client, string? requestUri, System.Text.Json.Serialization.Metadata.JsonTypeInfo jsonTypeInfo, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public static System.Threading.Tasks.Task GetFromJsonAsync(this System.Net.Http.HttpClient client, string? requestUri, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public static System.Threading.Tasks.Task GetFromJsonAsync(this System.Net.Http.HttpClient client, System.Uri? requestUri, System.Text.Json.JsonSerializerOptions? options, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public static System.Threading.Tasks.Task GetFromJsonAsync(this System.Net.Http.HttpClient client, System.Uri? requestUri, System.Text.Json.Serialization.Metadata.JsonTypeInfo jsonTypeInfo, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public static System.Threading.Tasks.Task GetFromJsonAsync(this System.Net.Http.HttpClient client, System.Uri? requestUri, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public static System.Threading.Tasks.Task PostAsJsonAsync(this System.Net.Http.HttpClient client, string? requestUri, TValue value, System.Text.Json.JsonSerializerOptions? options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public static System.Threading.Tasks.Task PostAsJsonAsync(this System.Net.Http.HttpClient client, string? requestUri, TValue value, System.Threading.CancellationToken cancellationToken) { throw null; } @@ -28,7 +32,9 @@ public static partial class HttpClientJsonExtensions public static partial class HttpContentJsonExtensions { public static System.Threading.Tasks.Task ReadFromJsonAsync(this System.Net.Http.HttpContent content, System.Type type, System.Text.Json.JsonSerializerOptions? options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public static System.Threading.Tasks.Task ReadFromJsonAsync(this System.Net.Http.HttpContent content, System.Type type, System.Text.Json.Serialization.JsonSerializerContext context, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public static System.Threading.Tasks.Task ReadFromJsonAsync(this System.Net.Http.HttpContent content, System.Text.Json.JsonSerializerOptions? options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public static System.Threading.Tasks.Task ReadFromJsonAsync(this System.Net.Http.HttpContent content, System.Text.Json.Serialization.Metadata.JsonTypeInfo jsonTypeInfo, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } } public sealed partial class JsonContent : System.Net.Http.HttpContent { diff --git a/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/HttpClientJsonExtensions.Get.cs b/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/HttpClientJsonExtensions.Get.cs index 908b5bc156678..f141bcefc28ce 100644 --- a/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/HttpClientJsonExtensions.Get.cs +++ b/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/HttpClientJsonExtensions.Get.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Text.Json; +using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; using System.Threading; using System.Threading.Tasks; @@ -56,6 +58,50 @@ public static partial class HttpClientJsonExtensions return GetFromJsonAsyncCore(taskResponse, options, cancellationToken); } + public static Task GetFromJsonAsync(this HttpClient client, string? requestUri, Type type, JsonSerializerContext context, CancellationToken cancellationToken = default) + { + if (client == null) + { + throw new ArgumentNullException(nameof(client)); + } + + Task taskResponse = client.GetAsync(requestUri, HttpCompletionOption.ResponseHeadersRead, cancellationToken); + return GetFromJsonAsyncCore(taskResponse, type, context, cancellationToken); + } + + public static Task GetFromJsonAsync(this HttpClient client, Uri? requestUri, Type type, JsonSerializerContext context, CancellationToken cancellationToken = default) + { + if (client == null) + { + throw new ArgumentNullException(nameof(client)); + } + + Task taskResponse = client.GetAsync(requestUri, HttpCompletionOption.ResponseHeadersRead, cancellationToken); + return GetFromJsonAsyncCore(taskResponse, type, context, cancellationToken); + } + + public static Task GetFromJsonAsync(this HttpClient client, string? requestUri, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken = default) + { + if (client == null) + { + throw new ArgumentNullException(nameof(client)); + } + + Task taskResponse = client.GetAsync(requestUri, HttpCompletionOption.ResponseHeadersRead, cancellationToken); + return GetFromJsonAsyncCore(taskResponse, jsonTypeInfo, cancellationToken); + } + + public static Task GetFromJsonAsync(this HttpClient client, Uri? requestUri, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken = default) + { + if (client == null) + { + throw new ArgumentNullException(nameof(client)); + } + + Task taskResponse = client.GetAsync(requestUri, HttpCompletionOption.ResponseHeadersRead, cancellationToken); + return GetFromJsonAsyncCore(taskResponse, jsonTypeInfo, cancellationToken); + } + public static Task GetFromJsonAsync(this HttpClient client, string? requestUri, Type type, CancellationToken cancellationToken = default) => client.GetFromJsonAsync(requestUri, type, options: null, cancellationToken); @@ -91,5 +137,23 @@ public static partial class HttpClientJsonExtensions return await response.Content!.ReadFromJsonAsync(options, cancellationToken).ConfigureAwait(false); } } + + private static async Task GetFromJsonAsyncCore(Task taskResponse, Type type, JsonSerializerContext context, CancellationToken cancellationToken) + { + using (HttpResponseMessage response = await taskResponse.ConfigureAwait(false)) + { + response.EnsureSuccessStatusCode(); + return await response.Content!.ReadFromJsonAsync(type, context, cancellationToken).ConfigureAwait(false); + } + } + + private static async Task GetFromJsonAsyncCore(Task taskResponse, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken) + { + using (HttpResponseMessage response = await taskResponse.ConfigureAwait(false)) + { + response.EnsureSuccessStatusCode(); + return await response.Content!.ReadFromJsonAsync(jsonTypeInfo, cancellationToken).ConfigureAwait(false); + } + } } } diff --git a/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/HttpContentJsonExtensions.cs b/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/HttpContentJsonExtensions.cs index 5457a1b65a7b8..ec0c756277659 100644 --- a/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/HttpContentJsonExtensions.cs +++ b/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/HttpContentJsonExtensions.cs @@ -4,6 +4,8 @@ using System.IO; using System.Text; using System.Text.Json; +using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; using System.Threading; using System.Threading.Tasks; @@ -37,21 +39,61 @@ public static partial class HttpContentJsonExtensions private static async Task ReadFromJsonAsyncCore(HttpContent content, Type type, Encoding? sourceEncoding, JsonSerializerOptions? options, CancellationToken cancellationToken) { - Stream contentStream = await ReadHttpContentStreamAsync(content, cancellationToken).ConfigureAwait(false); + using (Stream contentStream = await GetContentStream(content, sourceEncoding, cancellationToken).ConfigureAwait(false)) + { + return await JsonSerializer.DeserializeAsync(contentStream, type, options ?? JsonContent.s_defaultSerializerOptions, cancellationToken).ConfigureAwait(false); + } + } - // Wrap content stream into a transcoding stream that buffers the data transcoded from the sourceEncoding to utf-8. - if (sourceEncoding != null && sourceEncoding != Encoding.UTF8) + private static async Task ReadFromJsonAsyncCore(HttpContent content, Encoding? sourceEncoding, JsonSerializerOptions? options, CancellationToken cancellationToken) + { + using (Stream contentStream = await GetContentStream(content, sourceEncoding, cancellationToken).ConfigureAwait(false)) { - contentStream = GetTranscodingStream(contentStream, sourceEncoding); + return await JsonSerializer.DeserializeAsync(contentStream, options ?? JsonContent.s_defaultSerializerOptions, cancellationToken).ConfigureAwait(false); } + } - using (contentStream) + public static Task ReadFromJsonAsync(this HttpContent content, Type type, JsonSerializerContext context, CancellationToken cancellationToken = default) + { + if (content == null) { - return await JsonSerializer.DeserializeAsync(contentStream, type, options ?? JsonContent.s_defaultSerializerOptions, cancellationToken).ConfigureAwait(false); + throw new ArgumentNullException(nameof(content)); } + + Encoding? sourceEncoding = JsonContent.GetEncoding(content.Headers.ContentType?.CharSet); + + return ReadFromJsonAsyncCore(content, type, sourceEncoding, context, cancellationToken); } - private static async Task ReadFromJsonAsyncCore(HttpContent content, Encoding? sourceEncoding, JsonSerializerOptions? options, CancellationToken cancellationToken) + public static Task ReadFromJsonAsync(this HttpContent content, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken = default) + { + if (content == null) + { + throw new ArgumentNullException(nameof(content)); + } + + Encoding? sourceEncoding = JsonContent.GetEncoding(content.Headers.ContentType?.CharSet); + + return ReadFromJsonAsyncCore(content, sourceEncoding, jsonTypeInfo, cancellationToken); + } + + private static async Task ReadFromJsonAsyncCore(HttpContent content, Type type, Encoding? sourceEncoding, JsonSerializerContext context, CancellationToken cancellationToken) + { + using (Stream contentStream = await GetContentStream(content, sourceEncoding, cancellationToken).ConfigureAwait(false)) + { + return await JsonSerializer.DeserializeAsync(contentStream, type, context, cancellationToken).ConfigureAwait(false); + } + } + + private static async Task ReadFromJsonAsyncCore(HttpContent content, Encoding? sourceEncoding, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken) + { + using (Stream contentStream = await GetContentStream(content, sourceEncoding, cancellationToken).ConfigureAwait(false)) + { + return await JsonSerializer.DeserializeAsync(contentStream, jsonTypeInfo, cancellationToken).ConfigureAwait(false); + } + } + + private static async Task GetContentStream(HttpContent content, Encoding? sourceEncoding, CancellationToken cancellationToken) { Stream contentStream = await ReadHttpContentStreamAsync(content, cancellationToken).ConfigureAwait(false); @@ -61,10 +103,7 @@ public static partial class HttpContentJsonExtensions contentStream = GetTranscodingStream(contentStream, sourceEncoding); } - using (contentStream) - { - return await JsonSerializer.DeserializeAsync(contentStream, options ?? JsonContent.s_defaultSerializerOptions, cancellationToken).ConfigureAwait(false); - } + return contentStream; } } } diff --git a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/HttpClientJsonExtensionsTests.cs b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/HttpClientJsonExtensionsTests.cs index 6b38be23d83a3..680e42e2aaa33 100644 --- a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/HttpClientJsonExtensionsTests.cs +++ b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/HttpClientJsonExtensionsTests.cs @@ -1,13 +1,13 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Threading.Tasks; -using Xunit; +using System.Collections.Generic; +using System.Linq; using System.Net.Test.Common; using System.Text.Json; -using System.Linq; -using System.Collections.Generic; using System.Threading; +using System.Threading.Tasks; +using Xunit; namespace System.Net.Http.Json.Functional.Tests { @@ -15,7 +15,7 @@ public class HttpClientJsonExtensionsTests { [Theory] [MemberData(nameof(ReadFromJsonTestData))] - public async Task TestGetFromJsonAsync(string json) + public async Task TestGetFromJsonAsync(string json, bool containsQuotedNumbers) { HttpHeaderData header = new HttpHeaderData("Content-Type", "application/json"); List headers = new List { header }; @@ -36,6 +36,21 @@ await HttpMessageHandlerLoopbackServer.CreateClientAndServerAsync( per = await client.GetFromJsonAsync(uri.ToString()); per.Validate(); + + if (!containsQuotedNumbers) + { + per = (Person)await client.GetFromJsonAsync(uri, typeof(Person), JsonContext.Default); + per.Validate(); + + per = (Person)await client.GetFromJsonAsync(uri.ToString(), typeof(Person), JsonContext.Default); + per.Validate(); + + per = await client.GetFromJsonAsync(uri, JsonContext.Default.Person); + per.Validate(); + + per = await client.GetFromJsonAsync(uri.ToString(), JsonContext.Default.Person); + per.Validate(); + } } }, server => server.HandleRequestAsync(content: json, headers: headers)); @@ -44,8 +59,8 @@ await HttpMessageHandlerLoopbackServer.CreateClientAndServerAsync( public static IEnumerable ReadFromJsonTestData() { Person per = Person.Create(); - yield return new object[] { per.Serialize() }; - yield return new object[] { per.SerializeWithNumbersAsStrings() }; + yield return new object[] { per.Serialize(), false }; + yield return new object[] { per.SerializeWithNumbersAsStrings(), true }; } [Fact] @@ -58,6 +73,8 @@ await HttpMessageHandlerLoopbackServer.CreateClientAndServerAsync( { await Assert.ThrowsAsync(() => client.GetFromJsonAsync(uri, typeof(Person))); await Assert.ThrowsAsync(() => client.GetFromJsonAsync(uri)); + await Assert.ThrowsAsync(() => client.GetFromJsonAsync(uri, typeof(Person), JsonContext.Default)); + await Assert.ThrowsAsync(() => client.GetFromJsonAsync(uri, JsonContext.Default.Person)); } }, server => server.HandleRequestAsync(statusCode: HttpStatusCode.InternalServerError)); @@ -170,6 +187,8 @@ await HttpMessageHandlerLoopbackServer.CreateClientAndServerAsync( Person per = Assert.IsType(await client.GetFromJsonAsync((string)null, typeof(Person))); per = Assert.IsType(await client.GetFromJsonAsync((Uri)null, typeof(Person))); + per = Assert.IsType(await client.GetFromJsonAsync((string)null, typeof(Person), JsonContext.Default)); + per = Assert.IsType(await client.GetFromJsonAsync((Uri)null, typeof(Person), JsonContext.Default)); per = await client.GetFromJsonAsync((string)null); per = await client.GetFromJsonAsync((Uri)null); diff --git a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/JsonContext/Int32.cs b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/JsonContext/Int32.cs new file mode 100644 index 0000000000000..02e8bdf65d942 --- /dev/null +++ b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/JsonContext/Int32.cs @@ -0,0 +1,33 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; + +namespace System.Net.Http.Json.Functional.Tests +{ + internal partial class JsonContext : JsonSerializerContext + { + private JsonTypeInfo _Int32; + public JsonTypeInfo Int32 + { + get + { + if (_Int32 == null) + { + JsonConverter customConverter; + if (Options.Converters.Count > 0 && (customConverter = GetRuntimeProvidedCustomConverter(typeof(int))) != null) + { + _Int32 = JsonMetadataServices.CreateValueInfo(Options, customConverter); + } + else + { + _Int32 = JsonMetadataServices.CreateValueInfo(Options, JsonMetadataServices.Int32Converter); + } + } + + return _Int32; + } + } + } +} diff --git a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/JsonContext/JsonContext.cs b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/JsonContext/JsonContext.cs new file mode 100644 index 0000000000000..bb8268da02029 --- /dev/null +++ b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/JsonContext/JsonContext.cs @@ -0,0 +1,60 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; + +namespace System.Net.Http.Json.Functional.Tests +{ + internal partial class JsonContext : JsonSerializerContext + { + private static JsonContext s_default; + public static JsonContext Default => s_default ??= new JsonContext(new JsonSerializerOptions()); + + public JsonContext() : base(null) + { + } + + public JsonContext(JsonSerializerOptions options) : base(options) + { + } + + private JsonConverter GetRuntimeProvidedCustomConverter(System.Type type) + { + IList converters = Options.Converters; + + for (int i = 0; i < converters.Count; i++) + { + JsonConverter converter = converters[i]; + + if (converter.CanConvert(type)) + { + if (converter is JsonConverterFactory factory) + { + converter = factory.CreateConverter(type, Options); + if (converter == null || converter is JsonConverterFactory) + { + throw new InvalidOperationException($"The converter '{factory.GetType()}' cannot return null or a JsonConverterFactory instance."); + } + } + + return converter; + } + } + + return null; + } + + public override JsonTypeInfo GetTypeInfo(Type type) + { + if (type == typeof(Person)) + { + return this.Person; + } + + return null!; + } + } +} diff --git a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/JsonContext/Person.cs b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/JsonContext/Person.cs new file mode 100644 index 0000000000000..b53eeb900bcb8 --- /dev/null +++ b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/JsonContext/Person.cs @@ -0,0 +1,103 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; + +namespace System.Net.Http.Json.Functional.Tests +{ + internal partial class JsonContext : JsonSerializerContext + { + private JsonTypeInfo _Person; + public JsonTypeInfo Person + { + get + { + if (_Person == null) + { + JsonConverter customConverter; + if (Options.Converters.Count > 0 && (customConverter = GetRuntimeProvidedCustomConverter(typeof(Person))) != null) + { + _Person = JsonMetadataServices.CreateValueInfo(Options, customConverter); + } + else + { + JsonTypeInfo objectInfo = JsonMetadataServices.CreateObjectInfo(); + _Person = objectInfo; + + JsonMetadataServices.InitializeObjectInfo( + objectInfo, + Options, + createObjectFunc: static () => new Person(), + PersonPropInitFunc, + default); + } + } + + return _Person; + } + } + private static JsonPropertyInfo[] PersonPropInitFunc(JsonSerializerContext context) + { + JsonContext jsonContext = (JsonContext)context; + JsonSerializerOptions options = context.Options; + + JsonPropertyInfo[] properties = new JsonPropertyInfo[4]; + + properties[0] = JsonMetadataServices.CreatePropertyInfo( + options, + isProperty: true, + declaringType: typeof(Person), + propertyTypeInfo: jsonContext.Int32, + converter: null, + getter: static (obj) => { return ((Person)obj).Age; }, + setter: static (obj, value) => { ((Person)obj).Age = value; }, + ignoreCondition: default, + numberHandling: default, + propertyName: "Age", + jsonPropertyName: null); + + properties[1] = JsonMetadataServices.CreatePropertyInfo( + options, + isProperty: true, + declaringType: typeof(Person), + propertyTypeInfo: jsonContext.String, + converter: null, + getter: static (obj) => { return ((Person)obj).Name; }, + setter: static (obj, value) => { ((Person)obj).Name = value; }, + ignoreCondition: default, + numberHandling: default, + propertyName: "Name", + jsonPropertyName: null); + + properties[2] = JsonMetadataServices.CreatePropertyInfo( + options, + isProperty: true, + declaringType: typeof(Person), + propertyTypeInfo: jsonContext.Person, + converter: null, + getter: static (obj) => { return ((Person)obj).Parent; }, + setter: static (obj, value) => { ((Person)obj).Parent = value; }, + ignoreCondition: default, + numberHandling: default, + propertyName: "Parent", + jsonPropertyName: null); + + properties[3] = JsonMetadataServices.CreatePropertyInfo( + options, + isProperty: true, + declaringType: typeof(Person), + propertyTypeInfo: jsonContext.String, + converter: null, + getter: static (obj) => { return ((Person)obj).PlaceOfBirth; }, + setter: static (obj, value) => { ((Person)obj).PlaceOfBirth = value; }, + ignoreCondition: default, + numberHandling: default, + propertyName: "PlaceOfBirth", + jsonPropertyName: null); + + return properties; + } + } +} diff --git a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/JsonContext/String.cs b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/JsonContext/String.cs new file mode 100644 index 0000000000000..861a451d7beb6 --- /dev/null +++ b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/JsonContext/String.cs @@ -0,0 +1,33 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; + +namespace System.Net.Http.Json.Functional.Tests +{ + internal partial class JsonContext : JsonSerializerContext + { + private JsonTypeInfo _String; + public JsonTypeInfo String + { + get + { + if (_String == null) + { + JsonConverter customConverter; + if (Options.Converters.Count > 0 && (customConverter = GetRuntimeProvidedCustomConverter(typeof(string))) != null) + { + _String = JsonMetadataServices.CreateValueInfo(Options, customConverter); + } + else + { + _String = JsonMetadataServices.CreateValueInfo(Options, JsonMetadataServices.StringConverter); + } + } + + return _String; + } + } + } +} diff --git a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/System.Net.Http.Json.Functional.Tests.csproj b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/System.Net.Http.Json.Functional.Tests.csproj index 9279c127331a0..4b10c2cc7b8c7 100644 --- a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/System.Net.Http.Json.Functional.Tests.csproj +++ b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/System.Net.Http.Json.Functional.Tests.csproj @@ -6,30 +6,25 @@ + + + + - - - - - - - - - + + + + + + + + + diff --git a/src/libraries/System.Text.Json/ref/System.Text.Json.cs b/src/libraries/System.Text.Json/ref/System.Text.Json.cs index 481eddecc3134..1c71f86aab725 100644 --- a/src/libraries/System.Text.Json/ref/System.Text.Json.cs +++ b/src/libraries/System.Text.Json/ref/System.Text.Json.cs @@ -187,26 +187,40 @@ public partial struct JsonReaderState public static partial class JsonSerializer { public static object? Deserialize(System.ReadOnlySpan utf8Json, [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] System.Type returnType, System.Text.Json.JsonSerializerOptions? options = null) { throw null; } + public static object? Deserialize(System.ReadOnlySpan utf8Json, System.Type returnType, System.Text.Json.Serialization.JsonSerializerContext context) { throw null; } public static object? Deserialize(System.ReadOnlySpan json, [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] System.Type returnType, System.Text.Json.JsonSerializerOptions? options = null) { throw null; } + public static object? Deserialize(System.ReadOnlySpan json, System.Type returnType, System.Text.Json.Serialization.JsonSerializerContext context) { throw null; } public static object? Deserialize(string json, [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] System.Type returnType, System.Text.Json.JsonSerializerOptions? options = null) { throw null; } - public static object? Deserialize(string json, System.Type returnType, System.Text.Json.Serialization.JsonSerializerContext jsonSerializerContext) { throw null; } + public static object? Deserialize(string json, System.Type returnType, System.Text.Json.Serialization.JsonSerializerContext context) { throw null; } public static object? Deserialize(ref System.Text.Json.Utf8JsonReader reader, [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] System.Type returnType, System.Text.Json.JsonSerializerOptions? options = null) { throw null; } + public static object? Deserialize(ref System.Text.Json.Utf8JsonReader reader, System.Type returnType, System.Text.Json.Serialization.JsonSerializerContext context) { throw null; } public static System.Threading.Tasks.ValueTask DeserializeAsync(System.IO.Stream utf8Json, [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] System.Type returnType, System.Text.Json.JsonSerializerOptions? options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } - public static System.Threading.Tasks.ValueTask DeserializeAsync<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] TValue>(System.IO.Stream utf8Json, System.Text.Json.JsonSerializerOptions? options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public static System.Threading.Tasks.ValueTask DeserializeAsync(System.IO.Stream utf8Json, System.Type returnType, System.Text.Json.Serialization.JsonSerializerContext context, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public static System.Collections.Generic.IAsyncEnumerable DeserializeAsyncEnumerable<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] TValue>(System.IO.Stream utf8Json, System.Text.Json.JsonSerializerOptions? options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public static System.Threading.Tasks.ValueTask DeserializeAsync<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] TValue>(System.IO.Stream utf8Json, System.Text.Json.JsonSerializerOptions? options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public static System.Threading.Tasks.ValueTask DeserializeAsync(System.IO.Stream utf8Json, System.Text.Json.Serialization.Metadata.JsonTypeInfo jsonTypeInfo, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public static TValue? Deserialize<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] TValue>(System.ReadOnlySpan utf8Json, System.Text.Json.JsonSerializerOptions? options = null) { throw null; } + public static TValue? Deserialize(System.ReadOnlySpan utf8Json, System.Text.Json.Serialization.Metadata.JsonTypeInfo jsonTypeInfo) { throw null; } public static TValue? Deserialize<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] TValue>(System.ReadOnlySpan json, System.Text.Json.JsonSerializerOptions? options = null) { throw null; } + public static TValue? Deserialize(System.ReadOnlySpan json, System.Text.Json.Serialization.Metadata.JsonTypeInfo jsonTypeInfo) { throw null; } public static TValue? Deserialize<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] TValue>(string json, System.Text.Json.JsonSerializerOptions? options = null) { throw null; } public static TValue? Deserialize(string json, System.Text.Json.Serialization.Metadata.JsonTypeInfo jsonTypeInfo) { throw null; } public static TValue? Deserialize<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] TValue>(ref System.Text.Json.Utf8JsonReader reader, System.Text.Json.JsonSerializerOptions? options = null) { throw null; } + public static TValue? Deserialize(ref System.Text.Json.Utf8JsonReader reader, System.Text.Json.Serialization.Metadata.JsonTypeInfo jsonTypeInfo) { throw null; } public static string Serialize(object? value, [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] System.Type inputType, System.Text.Json.JsonSerializerOptions? options = null) { throw null; } - public static string Serialize(object? value, System.Type inputType, System.Text.Json.Serialization.JsonSerializerContext jsonSerializerContext) { throw null; } + public static string Serialize(object? value, System.Type inputType, System.Text.Json.Serialization.JsonSerializerContext context) { throw null; } public static void Serialize(System.Text.Json.Utf8JsonWriter writer, object? value, [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] System.Type inputType, System.Text.Json.JsonSerializerOptions? options = null) { } + public static void Serialize(System.Text.Json.Utf8JsonWriter writer, object? value, System.Type inputType, System.Text.Json.Serialization.JsonSerializerContext context) { } public static System.Threading.Tasks.Task SerializeAsync(System.IO.Stream utf8Json, object? value, [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] System.Type inputType, System.Text.Json.JsonSerializerOptions? options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public static System.Threading.Tasks.Task SerializeAsync(System.IO.Stream utf8Json, object? value, [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] System.Type inputType, System.Text.Json.Serialization.JsonSerializerContext context, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public static System.Threading.Tasks.Task SerializeAsync<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] TValue>(System.IO.Stream utf8Json, TValue value, System.Text.Json.JsonSerializerOptions? options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public static System.Threading.Tasks.Task SerializeAsync(System.IO.Stream utf8Json, TValue value, System.Text.Json.Serialization.Metadata.JsonTypeInfo jsonTypeInfo, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public static byte[] SerializeToUtf8Bytes(object? value, [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] System.Type inputType, System.Text.Json.JsonSerializerOptions? options = null) { throw null; } + public static byte[] SerializeToUtf8Bytes(object? value, System.Type inputType, System.Text.Json.Serialization.JsonSerializerContext context) { throw null; } public static byte[] SerializeToUtf8Bytes<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] TValue>(TValue value, System.Text.Json.JsonSerializerOptions? options = null) { throw null; } + public static byte[] SerializeToUtf8Bytes(TValue value, System.Text.Json.Serialization.Metadata.JsonTypeInfo jsonTypeInfo) { throw null; } public static void Serialize<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] TValue>(System.Text.Json.Utf8JsonWriter writer, TValue value, System.Text.Json.JsonSerializerOptions? options = null) { } + public static void Serialize(System.Text.Json.Utf8JsonWriter writer, TValue value, System.Text.Json.Serialization.Metadata.JsonTypeInfo jsonTypeInfo) { } public static string Serialize<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] TValue>(TValue value, System.Text.Json.JsonSerializerOptions? options = null) { throw null; } public static string Serialize(TValue value, System.Text.Json.Serialization.Metadata.JsonTypeInfo jsonTypeInfo) { throw null; } } @@ -482,12 +496,12 @@ public sealed partial class JsonArray : System.Text.Json.Node.JsonNode, System.C public JsonArray(System.Text.Json.Node.JsonNodeOptions options, params System.Text.Json.Node.JsonNode?[] items) { } public JsonArray(params System.Text.Json.Node.JsonNode?[] items) { } public int Count { get { throw null; } } - public static System.Text.Json.Node.JsonArray? Create(System.Text.Json.JsonElement element, System.Text.Json.Node.JsonNodeOptions? options = default(System.Text.Json.Node.JsonNodeOptions?)) { throw null; } bool System.Collections.Generic.ICollection.IsReadOnly { get { throw null; } } public void Add(System.Text.Json.Node.JsonNode? item) { } - public void Add(T value) { } + public void Add(T? value) { } public void Clear() { } public bool Contains(System.Text.Json.Node.JsonNode? item) { throw null; } + public static System.Text.Json.Node.JsonArray? Create(System.Text.Json.JsonElement element, System.Text.Json.Node.JsonNodeOptions? options = default(System.Text.Json.Node.JsonNodeOptions?)) { throw null; } public System.Collections.Generic.IEnumerator GetEnumerator() { throw null; } public int IndexOf(System.Text.Json.Node.JsonNode? item) { throw null; } public void Insert(int index, System.Text.Json.Node.JsonNode? item) { } @@ -509,94 +523,94 @@ internal JsonNode() { } public System.Text.Json.Node.JsonObject AsObject() { throw null; } public System.Text.Json.Node.JsonValue AsValue() { throw null; } public string GetPath() { throw null; } - public virtual TValue GetValue<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)]TValue>() { throw null; } - public static explicit operator bool(System.Text.Json.Node.JsonNode value) { throw null; } - public static explicit operator byte(System.Text.Json.Node.JsonNode value) { throw null; } - public static explicit operator char(System.Text.Json.Node.JsonNode value) { throw null; } - public static explicit operator System.DateTime(System.Text.Json.Node.JsonNode value) { throw null; } - public static explicit operator System.DateTimeOffset(System.Text.Json.Node.JsonNode value) { throw null; } - public static explicit operator decimal(System.Text.Json.Node.JsonNode value) { throw null; } - public static explicit operator double(System.Text.Json.Node.JsonNode value) { throw null; } - public static explicit operator System.Guid(System.Text.Json.Node.JsonNode value) { throw null; } - public static explicit operator short(System.Text.Json.Node.JsonNode value) { throw null; } - public static explicit operator int(System.Text.Json.Node.JsonNode value) { throw null; } - public static explicit operator long(System.Text.Json.Node.JsonNode value) { throw null; } - public static explicit operator bool?(System.Text.Json.Node.JsonNode? value) { throw null; } - public static explicit operator byte?(System.Text.Json.Node.JsonNode? value) { throw null; } - public static explicit operator char?(System.Text.Json.Node.JsonNode? value) { throw null; } - public static explicit operator System.DateTimeOffset?(System.Text.Json.Node.JsonNode? value) { throw null; } - public static explicit operator System.DateTime?(System.Text.Json.Node.JsonNode? value) { throw null; } - public static explicit operator decimal?(System.Text.Json.Node.JsonNode? value) { throw null; } - public static explicit operator double?(System.Text.Json.Node.JsonNode? value) { throw null; } - public static explicit operator System.Guid?(System.Text.Json.Node.JsonNode? value) { throw null; } - public static explicit operator short?(System.Text.Json.Node.JsonNode? value) { throw null; } - public static explicit operator int?(System.Text.Json.Node.JsonNode? value) { throw null; } - public static explicit operator long?(System.Text.Json.Node.JsonNode? value) { throw null; } - [System.CLSCompliantAttribute(false)] - public static explicit operator sbyte?(System.Text.Json.Node.JsonNode? value) { throw null; } - public static explicit operator float?(System.Text.Json.Node.JsonNode? value) { throw null; } - [System.CLSCompliantAttribute(false)] - public static explicit operator ushort?(System.Text.Json.Node.JsonNode? value) { throw null; } - [System.CLSCompliantAttribute(false)] - public static explicit operator uint?(System.Text.Json.Node.JsonNode? value) { throw null; } - [System.CLSCompliantAttribute(false)] - public static explicit operator ulong?(System.Text.Json.Node.JsonNode? value) { throw null; } - [System.CLSCompliantAttribute(false)] - public static explicit operator sbyte(System.Text.Json.Node.JsonNode value) { throw null; } - public static explicit operator float(System.Text.Json.Node.JsonNode value) { throw null; } - public static explicit operator string?(System.Text.Json.Node.JsonNode? value) { throw null; } - [System.CLSCompliantAttribute(false)] - public static explicit operator ushort(System.Text.Json.Node.JsonNode value) { throw null; } - [System.CLSCompliantAttribute(false)] - public static explicit operator uint(System.Text.Json.Node.JsonNode value) { throw null; } - [System.CLSCompliantAttribute(false)] - public static explicit operator ulong(System.Text.Json.Node.JsonNode value) { throw null; } - public static implicit operator System.Text.Json.Node.JsonNode(bool value) { throw null; } - public static implicit operator System.Text.Json.Node.JsonNode(byte value) { throw null; } - public static implicit operator System.Text.Json.Node.JsonNode(char value) { throw null; } - public static implicit operator System.Text.Json.Node.JsonNode(System.DateTime value) { throw null; } - public static implicit operator System.Text.Json.Node.JsonNode(System.DateTimeOffset value) { throw null; } - public static implicit operator System.Text.Json.Node.JsonNode(decimal value) { throw null; } - public static implicit operator System.Text.Json.Node.JsonNode(double value) { throw null; } - public static implicit operator System.Text.Json.Node.JsonNode(System.Guid value) { throw null; } - public static implicit operator System.Text.Json.Node.JsonNode(short value) { throw null; } - public static implicit operator System.Text.Json.Node.JsonNode(int value) { throw null; } - public static implicit operator System.Text.Json.Node.JsonNode(long value) { throw null; } - public static implicit operator System.Text.Json.Node.JsonNode?(bool? value) { throw null; } - public static implicit operator System.Text.Json.Node.JsonNode?(byte? value) { throw null; } - public static implicit operator System.Text.Json.Node.JsonNode?(char? value) { throw null; } - public static implicit operator System.Text.Json.Node.JsonNode?(System.DateTimeOffset? value) { throw null; } - public static implicit operator System.Text.Json.Node.JsonNode?(System.DateTime? value) { throw null; } - public static implicit operator System.Text.Json.Node.JsonNode?(decimal? value) { throw null; } - public static implicit operator System.Text.Json.Node.JsonNode?(double? value) { throw null; } - public static implicit operator System.Text.Json.Node.JsonNode?(System.Guid? value) { throw null; } - public static implicit operator System.Text.Json.Node.JsonNode?(short? value) { throw null; } - public static implicit operator System.Text.Json.Node.JsonNode?(int? value) { throw null; } - public static implicit operator System.Text.Json.Node.JsonNode?(long? value) { throw null; } - [System.CLSCompliantAttribute(false)] - public static implicit operator System.Text.Json.Node.JsonNode?(sbyte? value) { throw null; } - public static implicit operator System.Text.Json.Node.JsonNode?(float? value) { throw null; } - [System.CLSCompliantAttribute(false)] - public static implicit operator System.Text.Json.Node.JsonNode?(ushort? value) { throw null; } - [System.CLSCompliantAttribute(false)] - public static implicit operator System.Text.Json.Node.JsonNode?(uint? value) { throw null; } - [System.CLSCompliantAttribute(false)] - public static implicit operator System.Text.Json.Node.JsonNode?(ulong? value) { throw null; } - [System.CLSCompliantAttribute(false)] - public static implicit operator System.Text.Json.Node.JsonNode(sbyte value) { throw null; } - public static implicit operator System.Text.Json.Node.JsonNode(float value) { throw null; } - public static implicit operator System.Text.Json.Node.JsonNode?(string? value) { throw null; } - [System.CLSCompliantAttribute(false)] - public static implicit operator System.Text.Json.Node.JsonNode(ushort value) { throw null; } - [System.CLSCompliantAttribute(false)] - public static implicit operator System.Text.Json.Node.JsonNode(uint value) { throw null; } - [System.CLSCompliantAttribute(false)] - public static implicit operator System.Text.Json.Node.JsonNode(ulong value) { throw null; } - System.Dynamic.DynamicMetaObject System.Dynamic.IDynamicMetaObjectProvider.GetMetaObject(System.Linq.Expressions.Expression parameter) { throw null; } - public static System.Text.Json.Node.JsonNode? Parse(string json, System.Text.Json.Node.JsonNodeOptions? nodeOptions = default(System.Text.Json.Node.JsonNodeOptions?), System.Text.Json.JsonDocumentOptions documentOptions = default(System.Text.Json.JsonDocumentOptions)) { throw null; } - public static System.Text.Json.Node.JsonNode? Parse(ref System.Text.Json.Utf8JsonReader reader, System.Text.Json.Node.JsonNodeOptions? nodeOptions = default(System.Text.Json.Node.JsonNodeOptions?)) { throw null; } + public virtual TValue GetValue<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] TValue>() { throw null; } + public static explicit operator bool (System.Text.Json.Node.JsonNode value) { throw null; } + public static explicit operator byte (System.Text.Json.Node.JsonNode value) { throw null; } + public static explicit operator char (System.Text.Json.Node.JsonNode value) { throw null; } + public static explicit operator System.DateTime (System.Text.Json.Node.JsonNode value) { throw null; } + public static explicit operator System.DateTimeOffset (System.Text.Json.Node.JsonNode value) { throw null; } + public static explicit operator decimal (System.Text.Json.Node.JsonNode value) { throw null; } + public static explicit operator double (System.Text.Json.Node.JsonNode value) { throw null; } + public static explicit operator System.Guid (System.Text.Json.Node.JsonNode value) { throw null; } + public static explicit operator short (System.Text.Json.Node.JsonNode value) { throw null; } + public static explicit operator int (System.Text.Json.Node.JsonNode value) { throw null; } + public static explicit operator long (System.Text.Json.Node.JsonNode value) { throw null; } + public static explicit operator bool? (System.Text.Json.Node.JsonNode? value) { throw null; } + public static explicit operator byte? (System.Text.Json.Node.JsonNode? value) { throw null; } + public static explicit operator char? (System.Text.Json.Node.JsonNode? value) { throw null; } + public static explicit operator System.DateTimeOffset? (System.Text.Json.Node.JsonNode? value) { throw null; } + public static explicit operator System.DateTime? (System.Text.Json.Node.JsonNode? value) { throw null; } + public static explicit operator decimal? (System.Text.Json.Node.JsonNode? value) { throw null; } + public static explicit operator double? (System.Text.Json.Node.JsonNode? value) { throw null; } + public static explicit operator System.Guid? (System.Text.Json.Node.JsonNode? value) { throw null; } + public static explicit operator short? (System.Text.Json.Node.JsonNode? value) { throw null; } + public static explicit operator int? (System.Text.Json.Node.JsonNode? value) { throw null; } + public static explicit operator long? (System.Text.Json.Node.JsonNode? value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator sbyte? (System.Text.Json.Node.JsonNode? value) { throw null; } + public static explicit operator float? (System.Text.Json.Node.JsonNode? value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator ushort? (System.Text.Json.Node.JsonNode? value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator uint? (System.Text.Json.Node.JsonNode? value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator ulong? (System.Text.Json.Node.JsonNode? value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator sbyte (System.Text.Json.Node.JsonNode value) { throw null; } + public static explicit operator float (System.Text.Json.Node.JsonNode value) { throw null; } + public static explicit operator string? (System.Text.Json.Node.JsonNode? value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator ushort (System.Text.Json.Node.JsonNode value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator uint (System.Text.Json.Node.JsonNode value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator ulong (System.Text.Json.Node.JsonNode value) { throw null; } + public static implicit operator System.Text.Json.Node.JsonNode (bool value) { throw null; } + public static implicit operator System.Text.Json.Node.JsonNode (byte value) { throw null; } + public static implicit operator System.Text.Json.Node.JsonNode (char value) { throw null; } + public static implicit operator System.Text.Json.Node.JsonNode (System.DateTime value) { throw null; } + public static implicit operator System.Text.Json.Node.JsonNode (System.DateTimeOffset value) { throw null; } + public static implicit operator System.Text.Json.Node.JsonNode (decimal value) { throw null; } + public static implicit operator System.Text.Json.Node.JsonNode (double value) { throw null; } + public static implicit operator System.Text.Json.Node.JsonNode (System.Guid value) { throw null; } + public static implicit operator System.Text.Json.Node.JsonNode (short value) { throw null; } + public static implicit operator System.Text.Json.Node.JsonNode (int value) { throw null; } + public static implicit operator System.Text.Json.Node.JsonNode (long value) { throw null; } + public static implicit operator System.Text.Json.Node.JsonNode? (bool? value) { throw null; } + public static implicit operator System.Text.Json.Node.JsonNode? (byte? value) { throw null; } + public static implicit operator System.Text.Json.Node.JsonNode? (char? value) { throw null; } + public static implicit operator System.Text.Json.Node.JsonNode? (System.DateTimeOffset? value) { throw null; } + public static implicit operator System.Text.Json.Node.JsonNode? (System.DateTime? value) { throw null; } + public static implicit operator System.Text.Json.Node.JsonNode? (decimal? value) { throw null; } + public static implicit operator System.Text.Json.Node.JsonNode? (double? value) { throw null; } + public static implicit operator System.Text.Json.Node.JsonNode? (System.Guid? value) { throw null; } + public static implicit operator System.Text.Json.Node.JsonNode? (short? value) { throw null; } + public static implicit operator System.Text.Json.Node.JsonNode? (int? value) { throw null; } + public static implicit operator System.Text.Json.Node.JsonNode? (long? value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static implicit operator System.Text.Json.Node.JsonNode? (sbyte? value) { throw null; } + public static implicit operator System.Text.Json.Node.JsonNode? (float? value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static implicit operator System.Text.Json.Node.JsonNode? (ushort? value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static implicit operator System.Text.Json.Node.JsonNode? (uint? value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static implicit operator System.Text.Json.Node.JsonNode? (ulong? value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static implicit operator System.Text.Json.Node.JsonNode (sbyte value) { throw null; } + public static implicit operator System.Text.Json.Node.JsonNode (float value) { throw null; } + public static implicit operator System.Text.Json.Node.JsonNode? (string? value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static implicit operator System.Text.Json.Node.JsonNode (ushort value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static implicit operator System.Text.Json.Node.JsonNode (uint value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static implicit operator System.Text.Json.Node.JsonNode (ulong value) { throw null; } public static System.Text.Json.Node.JsonNode? Parse(System.IO.Stream utf8Json, System.Text.Json.Node.JsonNodeOptions? nodeOptions = default(System.Text.Json.Node.JsonNodeOptions?), System.Text.Json.JsonDocumentOptions documentOptions = default(System.Text.Json.JsonDocumentOptions)) { throw null; } public static System.Text.Json.Node.JsonNode? Parse(System.ReadOnlySpan utf8Json, System.Text.Json.Node.JsonNodeOptions? nodeOptions = default(System.Text.Json.Node.JsonNodeOptions?), System.Text.Json.JsonDocumentOptions documentOptions = default(System.Text.Json.JsonDocumentOptions)) { throw null; } + public static System.Text.Json.Node.JsonNode? Parse(string json, System.Text.Json.Node.JsonNodeOptions? nodeOptions = default(System.Text.Json.Node.JsonNodeOptions?), System.Text.Json.JsonDocumentOptions documentOptions = default(System.Text.Json.JsonDocumentOptions)) { throw null; } + public static System.Text.Json.Node.JsonNode? Parse(ref System.Text.Json.Utf8JsonReader reader, System.Text.Json.Node.JsonNodeOptions? nodeOptions = default(System.Text.Json.Node.JsonNodeOptions?)) { throw null; } + System.Dynamic.DynamicMetaObject System.Dynamic.IDynamicMetaObjectProvider.GetMetaObject(System.Linq.Expressions.Expression parameter) { throw null; } public string ToJsonString(System.Text.Json.JsonSerializerOptions? options = null) { throw null; } public override string ToString() { throw null; } public abstract void WriteTo(System.Text.Json.Utf8JsonWriter writer, System.Text.Json.JsonSerializerOptions? options = null); @@ -608,10 +622,9 @@ public partial struct JsonNodeOptions } public sealed partial class JsonObject : System.Text.Json.Node.JsonNode, System.Collections.Generic.ICollection>, System.Collections.Generic.IDictionary, System.Collections.Generic.IEnumerable>, System.Collections.IEnumerable { - public JsonObject(System.Text.Json.Node.JsonNodeOptions? options = default(System.Text.Json.Node.JsonNodeOptions?)) { } public JsonObject(System.Collections.Generic.IEnumerable> properties, System.Text.Json.Node.JsonNodeOptions? options = default(System.Text.Json.Node.JsonNodeOptions?)) { } + public JsonObject(System.Text.Json.Node.JsonNodeOptions? options = default(System.Text.Json.Node.JsonNodeOptions?)) { } public int Count { get { throw null; } } - public static System.Text.Json.Node.JsonObject? Create(System.Text.Json.JsonElement element, System.Text.Json.Node.JsonNodeOptions? options = default(System.Text.Json.Node.JsonNodeOptions?)) { throw null; } bool System.Collections.Generic.ICollection>.IsReadOnly { get { throw null; } } System.Collections.Generic.ICollection System.Collections.Generic.IDictionary.Keys { get { throw null; } } System.Collections.Generic.ICollection System.Collections.Generic.IDictionary.Values { get { throw null; } } @@ -619,21 +632,22 @@ public void Add(System.Collections.Generic.KeyValuePair> GetEnumerator() { throw null; } public bool Remove(string propertyName) { throw null; } bool System.Collections.Generic.ICollection>.Contains(System.Collections.Generic.KeyValuePair item) { throw null; } void System.Collections.Generic.ICollection>.CopyTo(System.Collections.Generic.KeyValuePair[] array, int index) { } bool System.Collections.Generic.ICollection>.Remove(System.Collections.Generic.KeyValuePair item) { throw null; } - bool System.Collections.Generic.IDictionary.TryGetValue(string propertyName, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out System.Text.Json.Node.JsonNode jsonNode) { throw null; } + bool System.Collections.Generic.IDictionary.TryGetValue(string propertyName, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Text.Json.Node.JsonNode jsonNode) { throw null; } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; } public bool TryGetPropertyValue(string propertyName, out System.Text.Json.Node.JsonNode? jsonNode) { throw null; } public override void WriteTo(System.Text.Json.Utf8JsonWriter writer, System.Text.Json.JsonSerializerOptions? options = null) { } } public abstract partial class JsonValue : System.Text.Json.Node.JsonNode { - private protected JsonValue(JsonNodeOptions? options = null) { throw null; } - public static System.Text.Json.Node.JsonValue? Create(T value, System.Text.Json.Node.JsonNodeOptions? options = default(System.Text.Json.Node.JsonNodeOptions?)) { throw null; } - public abstract bool TryGetValue<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)]T>([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out T? value); + internal JsonValue() { } + public static System.Text.Json.Node.JsonValue? Create(T? value, System.Text.Json.Node.JsonNodeOptions? options = default(System.Text.Json.Node.JsonNodeOptions?)) { throw null; } + public abstract bool TryGetValue<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] T>([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out T? value); } } namespace System.Text.Json.Serialization diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/JsonHelpers.cs b/src/libraries/System.Text.Json/src/System/Text/Json/JsonHelpers.cs index eeed3815ff3dc..1546ce8968d59 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/JsonHelpers.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/JsonHelpers.cs @@ -164,7 +164,7 @@ public static void ValidateInt32MaxArrayLength(uint length) } } - public static JsonTypeInfo GetJsonTypeInfo(JsonSerializerContext context, Type type) + public static JsonTypeInfo GetTypeInfo(JsonSerializerContext context, Type type) { Debug.Assert(context != null); Debug.Assert(type != null); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Span.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Span.cs index 0a5cfcbfd3fdf..6f967b88709e9 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Span.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Span.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics.CodeAnalysis; +using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; namespace System.Text.Json { @@ -75,5 +77,85 @@ public static partial class JsonSerializer return ReadCore(ref reader, returnType, options); } + + /// + /// Parse the UTF-8 encoded text representing a single JSON value into a . + /// + /// A representation of the JSON value. + /// JSON text to parse. + /// Metadata about the type to convert. + /// + /// Thrown when the JSON is invalid, + /// is not compatible with the JSON, + /// or when there is remaining data in the Stream. + /// + /// + /// There is no compatible + /// for or its serializable members. + /// + public static TValue? Deserialize(ReadOnlySpan utf8Json, JsonTypeInfo jsonTypeInfo) + { + if (jsonTypeInfo == null) + { + throw new ArgumentNullException(nameof(jsonTypeInfo)); + } + + JsonSerializerOptions options = jsonTypeInfo.Options; + + var readerState = new JsonReaderState(options.GetReaderOptions()); + var reader = new Utf8JsonReader(utf8Json, isFinalBlock: true, readerState); + + ReadStack state = default; + state.Initialize(jsonTypeInfo); + + return ReadCore(jsonTypeInfo.PropertyInfoForTypeInfo.ConverterBase, ref reader, options, ref state); + } + + /// + /// Parse the UTF-8 encoded text representing a single JSON value into a . + /// + /// A representation of the JSON value. + /// JSON text to parse. + /// The type of the object to convert to and return. + /// A metadata provider for serializable types. + /// + /// is . + /// + /// + /// Thrown when the JSON is invalid, + /// is not compatible with the JSON, + /// or when there is remaining data in the Stream. + /// + /// + /// There is no compatible + /// for or its serializable members. + /// + /// + /// The method on the provided + /// did not return a compatible for . + /// + public static object? Deserialize(ReadOnlySpan utf8Json, Type returnType, JsonSerializerContext context) + { + if (returnType == null) + { + throw new ArgumentNullException(nameof(returnType)); + } + + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + + JsonTypeInfo jsonTypeInfo = JsonHelpers.GetTypeInfo(context, returnType); + JsonSerializerOptions options = jsonTypeInfo.Options; + + var readerState = new JsonReaderState(options.GetReaderOptions()); + var reader = new Utf8JsonReader(utf8Json, isFinalBlock: true, readerState); + + ReadStack state = default; + state.Initialize(jsonTypeInfo); + + return ReadCore(jsonTypeInfo.PropertyInfoForTypeInfo.ConverterBase, ref reader, options, ref state); + } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Stream.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Stream.cs index a30dbe3ce7925..68a199ef72a0b 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Stream.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Stream.cs @@ -8,6 +8,7 @@ using System.IO; using System.Runtime.CompilerServices; using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; using System.Threading; using System.Threading.Tasks; @@ -47,7 +48,7 @@ public static partial class JsonSerializer throw new ArgumentNullException(nameof(utf8Json)); } - return ReadAllAsync(utf8Json, typeof(TValue), options, cancellationToken); + return ReadAllUsingOptionsAsync(utf8Json, typeof(TValue), options, cancellationToken); } /// @@ -85,7 +86,104 @@ public static partial class JsonSerializer if (returnType == null) throw new ArgumentNullException(nameof(returnType)); - return ReadAllAsync(utf8Json, returnType, options, cancellationToken); + return ReadAllUsingOptionsAsync(utf8Json, returnType, options, cancellationToken); + } + + private static ValueTask ReadAllUsingOptionsAsync( + Stream utf8Json, + Type returnType, + JsonSerializerOptions? options, + CancellationToken cancellationToken) + { + options ??= JsonSerializerOptions.s_defaultOptions; + options.RootBuiltInConvertersAndTypeInfoCreator(); + JsonTypeInfo jsonTypeInfo = options.GetOrAddClassForRootType(returnType); + return ReadAllAsync(utf8Json, returnType, jsonTypeInfo, cancellationToken); + } + + /// + /// Read the UTF-8 encoded text representing a single JSON value into a . + /// The Stream will be read to completion. + /// + /// A representation of the JSON value. + /// JSON data to parse. + /// Metadata about the type to convert. + /// + /// The which may be used to cancel the read operation. + /// + /// + /// or is . + /// + /// + /// Thrown when the JSON is invalid, + /// is not compatible with the JSON, + /// or when there is remaining data in the Stream. + /// + /// + /// There is no compatible + /// for or its serializable members. + /// + public static ValueTask DeserializeAsync( + Stream utf8Json, + JsonTypeInfo jsonTypeInfo, + CancellationToken cancellationToken = default) + { + if (utf8Json == null) + { + throw new ArgumentNullException(nameof(utf8Json)); + } + + if (jsonTypeInfo == null) + { + throw new ArgumentNullException(nameof(jsonTypeInfo)); + } + + return ReadAllAsync(utf8Json, typeof(TValue), jsonTypeInfo, cancellationToken); + } + + /// + /// Read the UTF-8 encoded text representing a single JSON value into a . + /// The Stream will be read to completion. + /// + /// A representation of the JSON value. + /// JSON data to parse. + /// The type of the object to convert to and return. + /// A metadata provider for serializable types. + /// + /// The which may be used to cancel the read operation. + /// + /// + /// , , or is . + /// + /// + /// Thrown when the JSON is invalid, + /// the is not compatible with the JSON, + /// or when there is remaining data in the Stream. + /// + /// + /// There is no compatible + /// for or its serializable members. + /// + /// + /// The method on the provided + /// did not return a compatible for . + /// + public static ValueTask DeserializeAsync( + Stream utf8Json, + Type returnType, + JsonSerializerContext context, + CancellationToken cancellationToken = default) + { + if (utf8Json == null) + throw new ArgumentNullException(nameof(utf8Json)); + + if (returnType == null) + throw new ArgumentNullException(nameof(returnType)); + + if (context == null) + throw new ArgumentNullException(nameof(context)); + + return ReadAllAsync(utf8Json, returnType, JsonHelpers.GetTypeInfo(context, returnType), cancellationToken); } /// @@ -100,7 +198,7 @@ public static partial class JsonSerializer /// /// is . /// - public static IAsyncEnumerable DeserializeAsyncEnumerable<[DynamicallyAccessedMembers(JsonHelpers.MembersAccessedOnRead)] TValue>( + public static IAsyncEnumerable DeserializeAsyncEnumerable<[DynamicallyAccessedMembers(JsonHelpers.MembersAccessedOnRead)] TValue>( Stream utf8Json, JsonSerializerOptions? options = null, CancellationToken cancellationToken = default) @@ -152,15 +250,13 @@ static async IAsyncEnumerable CreateAsyncEnumerableDeserializer( internal static async ValueTask ReadAllAsync( Stream utf8Json, Type inputType, - JsonSerializerOptions? options, + JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken) { - options ??= JsonSerializerOptions.s_defaultOptions; - options.RootBuiltInConvertersAndTypeInfoCreator(); - + JsonSerializerOptions options = jsonTypeInfo.Options; var asyncState = new ReadAsyncBufferState(options.DefaultBufferSize); ReadStack readStack = default; - readStack.Initialize(inputType, options, supportContinuation: true); + readStack.Initialize(jsonTypeInfo, supportContinuation: true); JsonConverter converter = readStack.Current.JsonPropertyInfo!.ConverterBase; var jsonReaderState = new JsonReaderState(options.GetReaderOptions()); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.String.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.String.cs index 6be743dacb6bf..3092fbfd1387e 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.String.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.String.cs @@ -262,7 +262,41 @@ public static partial class JsonSerializer throw new ArgumentNullException(nameof(json)); } - // null check for jsonTypeInfo occurs here. + return DeserializeUsingMetadata(json.AsSpan(), jsonTypeInfo); + } + + /// + /// Parse the text representing a single JSON value into a . + /// + /// A representation of the JSON value. + /// JSON text to parse. + /// Metadata about the type to convert. + /// + /// is . + /// + /// -or- + /// + /// is . + /// + /// + /// The JSON is invalid. + /// + /// -or- + /// + /// is not compatible with the JSON. + /// + /// -or- + /// + /// There is remaining data in the string beyond a single JSON value. + /// + /// There is no compatible + /// for or its serializable members. + /// + /// Using a is not as efficient as using the + /// UTF-8 methods since the implementation natively uses UTF-8. + /// + public static TValue? Deserialize(ReadOnlySpan json, JsonTypeInfo jsonTypeInfo) + { return DeserializeUsingMetadata(json, jsonTypeInfo); } @@ -272,13 +306,13 @@ public static partial class JsonSerializer /// A representation of the JSON value. /// JSON text to parse. /// The type of the object to convert to and return. - /// A metadata provider for serializable types. + /// A metadata provider for serializable types. /// /// is . /// /// -or- /// - /// is . + /// is . /// /// /// The JSON is invalid. @@ -296,34 +330,74 @@ public static partial class JsonSerializer /// /// /// The method of the provided - /// returns for the type to convert. + /// returns for the type to convert. /// /// Using a is not as efficient as using the /// UTF-8 methods since the implementation natively uses UTF-8. /// - public static object? Deserialize(string json, Type returnType, JsonSerializerContext jsonSerializerContext) + public static object? Deserialize(string json, Type returnType, JsonSerializerContext context) { if (json == null) { throw new ArgumentNullException(nameof(json)); } + return Deserialize(json.AsSpan(), returnType, context); + } + + /// + /// Parse the text representing a single JSON value into a . + /// + /// A representation of the JSON value. + /// JSON text to parse. + /// The type of the object to convert to and return. + /// A metadata provider for serializable types. + /// + /// is . + /// + /// -or- + /// + /// is . + /// + /// + /// The JSON is invalid. + /// + /// -or- + /// + /// is not compatible with the JSON. + /// + /// -or- + /// + /// There is remaining data in the string beyond a single JSON value. + /// + /// There is no compatible + /// for or its serializable members. + /// + /// + /// The method of the provided + /// returns for the type to convert. + /// + /// Using a is not as efficient as using the + /// UTF-8 methods since the implementation natively uses UTF-8. + /// + public static object? Deserialize(ReadOnlySpan json, Type returnType, JsonSerializerContext context) + { if (returnType == null) { throw new ArgumentNullException(nameof(returnType)); } - if (jsonSerializerContext == null) + if (context == null) { - throw new ArgumentNullException(nameof(jsonSerializerContext)); + throw new ArgumentNullException(nameof(context)); } return DeserializeUsingMetadata( json, - JsonHelpers.GetJsonTypeInfo(jsonSerializerContext, returnType)); + JsonHelpers.GetTypeInfo(context, returnType)); } - private static TValue? DeserializeUsingMetadata(string json, JsonTypeInfo? jsonTypeInfo) + private static TValue? DeserializeUsingMetadata(ReadOnlySpan json, JsonTypeInfo? jsonTypeInfo) { if (jsonTypeInfo == null) { @@ -335,7 +409,7 @@ public static partial class JsonSerializer return Deserialize( jsonTypeInfo.PropertyInfoForTypeInfo.ConverterBase, - json.AsSpan(), + json, jsonTypeInfo.Options, ref state); } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Utf8JsonReader.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Utf8JsonReader.cs index 66b1d14d69bcb..41f28197c56af 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Utf8JsonReader.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Utf8JsonReader.cs @@ -5,6 +5,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; namespace System.Text.Json { @@ -132,6 +133,130 @@ public static partial class JsonSerializer return ReadValueCore(options, ref reader, ref state); } + /// + /// Reads one JSON value (including objects or arrays) from the provided reader into a . + /// + /// A representation of the JSON value. + /// The reader to read. + /// Metadata about the type to convert. + /// + /// Thrown when the JSON is invalid, + /// is not compatible with the JSON, + /// or a value could not be read from the reader. + /// + /// + /// is using unsupported options. + /// + /// + /// There is no compatible + /// for or its serializable members. + /// + /// + /// + /// If the property of + /// is or , the + /// reader will be advanced by one call to to determine + /// the start of the value. + /// + /// + /// + /// Upon completion of this method will be positioned at the + /// final token in the JSON value. If an exception is thrown the reader is reset to + /// the state it was in when the method was called. + /// + /// + /// + /// This method makes a copy of the data the reader acted on, so there is no caller + /// requirement to maintain data integrity beyond the return of this method. + /// + /// + /// + /// The used to create the instance of the take precedence over the when they conflict. + /// Hence, , , are used while reading. + /// + /// + public static TValue? Deserialize(ref Utf8JsonReader reader, JsonTypeInfo jsonTypeInfo) + { + if (jsonTypeInfo == null) + { + throw new ArgumentNullException(nameof(jsonTypeInfo)); + } + + ReadStack state = default; + state.Initialize(jsonTypeInfo); + + return ReadValueCore(jsonTypeInfo.Options, ref reader, ref state); + } + + /// + /// Reads one JSON value (including objects or arrays) from the provided reader into a . + /// + /// A representation of the JSON value. + /// The reader to read. + /// The type of the object to convert to and return. + /// A metadata provider for serializable types. + /// + /// or is . + /// + /// + /// Thrown when the JSON is invalid, + /// is not compatible with the JSON, + /// or a value could not be read from the reader. + /// + /// + /// is using unsupported options. + /// + /// + /// There is no compatible + /// for or its serializable members. + /// + /// + /// The method on the provided + /// did not return a compatible for . + /// + /// + /// + /// If the property of + /// is or , the + /// reader will be advanced by one call to to determine + /// the start of the value. + /// + /// + /// + /// Upon completion of this method will be positioned at the + /// final token in the JSON value. If an exception is thrown the reader is reset to + /// the state it was in when the method was called. + /// + /// + /// + /// This method makes a copy of the data the reader acted on, so there is no caller + /// requirement to maintain data integrity beyond the return of this method. + /// + /// + /// The used to create the instance of the take precedence over the when they conflict. + /// Hence, , , are used while reading. + /// + /// + public static object? Deserialize(ref Utf8JsonReader reader, Type returnType, JsonSerializerContext context) + { + if (returnType == null) + { + throw new ArgumentNullException(nameof(returnType)); + } + + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + + ReadStack state = default; + + JsonTypeInfo jsonTypeInfo = JsonHelpers.GetTypeInfo(context, returnType); + state.Initialize(jsonTypeInfo); + + return ReadValueCore(jsonTypeInfo.Options, ref reader, ref state); + } + private static void CheckSupportedOptions(JsonReaderOptions readerOptions, string paramName) { if (readerOptions.CommentHandling == JsonCommentHandling.Allow) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.ByteArray.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.ByteArray.cs index 0398dda5b5222..ab67afbe0422b 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.ByteArray.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.ByteArray.cs @@ -1,7 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; namespace System.Text.Json { @@ -21,7 +24,7 @@ public static partial class JsonSerializer TValue value, JsonSerializerOptions? options = null) { - return WriteCoreBytes(value, typeof(TValue), options); + return WriteCoreBytes(value, GetRuntimeType(value), options); } /// @@ -46,33 +49,82 @@ public static byte[] SerializeToUtf8Bytes( [DynamicallyAccessedMembers(MembersAccessedOnWrite)] Type inputType, JsonSerializerOptions? options = null) { - if (inputType == null) - { - throw new ArgumentNullException(nameof(inputType)); - } + return WriteCoreBytes( + value!, + GetRuntimeTypeAndValidateInputType(value, inputType), + options); + } - if (value != null && !inputType.IsAssignableFrom(value.GetType())) + /// + /// Convert the provided value into a array. + /// + /// A UTF-8 representation of the value. + /// The value to convert. + /// Metadata about the type to convert. + /// + /// There is no compatible + /// for or its serializable members. + /// + /// + /// is . + /// + public static byte[] SerializeToUtf8Bytes(TValue value, JsonTypeInfo jsonTypeInfo) + { + if (jsonTypeInfo == null) { - ThrowHelper.ThrowArgumentException_DeserializeWrongType(inputType, value); + throw new ArgumentNullException(nameof(jsonTypeInfo)); } - return WriteCoreBytes(value!, inputType, options); + return WriteCoreBytes(value, jsonTypeInfo); } - private static byte[] WriteCoreBytes(in TValue value, Type inputType, JsonSerializerOptions? options) + /// + /// Convert the provided value into a array. + /// + /// A UTF-8 representation of the value. + /// The value to convert. + /// The type of the to convert. + /// A metadata provider for serializable types. + /// + /// is not compatible with . + /// + /// + /// is . + /// + /// + /// There is no compatible + /// for or its serializable members. + /// + /// + /// The method of the provided + /// returns for the type to convert. + /// + public static byte[] SerializeToUtf8Bytes(object? value, Type inputType, JsonSerializerContext context) { - if (options == null) + if (context == null) { - options = JsonSerializerOptions.s_defaultOptions; + throw new ArgumentNullException(nameof(context)); } - options.RootBuiltInConvertersAndTypeInfoCreator(); + Type runtimeType = GetRuntimeTypeAndValidateInputType(value, inputType); + return WriteCoreBytes(value!, JsonHelpers.GetTypeInfo(context, runtimeType)); + } + + private static byte[] WriteCoreBytes(in TValue value, Type runtimeType, JsonSerializerOptions? options) + { + JsonTypeInfo jsonTypeInfo = GetTypeInfo(runtimeType, options); + return WriteCoreBytes(value, jsonTypeInfo); + } + + private static byte[] WriteCoreBytes(in TValue value, JsonTypeInfo jsonTypeInfo) + { + JsonSerializerOptions options = jsonTypeInfo.Options; using (var output = new PooledByteBufferWriter(options.DefaultBufferSize)) { using (var writer = new Utf8JsonWriter(output, options.GetWriterOptions())) { - WriteCore(writer, value, inputType, options); + SerializeUsingMetadata(writer, value, jsonTypeInfo); } return output.WrittenMemory.ToArray(); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Helpers.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Helpers.cs index 3ea45fa908b6e..bf4dea2837284 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Helpers.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Helpers.cs @@ -13,35 +13,6 @@ public static partial class JsonSerializer // Members accessed by the serializer when serializing. private const DynamicallyAccessedMemberTypes MembersAccessedOnWrite = DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicFields; - private static void WriteCore( - Utf8JsonWriter writer, - in TValue value, - Type inputType, - JsonSerializerOptions options) - { - Debug.Assert(writer != null); - - // We treat typeof(object) special and allow polymorphic behavior. - if (inputType == JsonTypeInfo.ObjectType && value != null) - { - inputType = value.GetType(); - } - - WriteStack state = default; - JsonConverter jsonConverter = state.Initialize(inputType, options, supportContinuation: false); - - try - { - bool success = WriteCore(jsonConverter, writer, value, options, ref state); - Debug.Assert(success); - } - catch - { - state.DisposePendingDisposablesOnException(); - throw; - } - } - private static bool WriteCore( JsonConverter jsonConverter, Utf8JsonWriter writer, @@ -67,5 +38,59 @@ private static bool WriteCore( writer.Flush(); return success; } + + private static void SerializeUsingMetadata(Utf8JsonWriter writer, in TValue value, JsonTypeInfo jsonTypeInfo) + { + WriteStack state = default; + state.Initialize(jsonTypeInfo, supportContinuation: false); + + JsonConverter converter = jsonTypeInfo.PropertyInfoForTypeInfo.ConverterBase; + Debug.Assert(converter != null); + + Debug.Assert(jsonTypeInfo.Options != null); + + WriteCore(converter, writer, value, jsonTypeInfo.Options, ref state); + } + + private static Type GetRuntimeType(in TValue value) + { + if (typeof(TValue) == typeof(object) && value != null) + { + return value.GetType(); + } + + return typeof(TValue); + } + + private static Type GetRuntimeTypeAndValidateInputType(object? value, Type inputType) + { + if (inputType == null) + { + throw new ArgumentNullException(nameof(inputType)); + } + + if (value != null) + { + Type runtimeType = value.GetType(); + if (!inputType.IsAssignableFrom(runtimeType)) + { + ThrowHelper.ThrowArgumentException_DeserializeWrongType(inputType, value); + } + + if (inputType == typeof(object)) + { + return runtimeType; + } + } + + return inputType; + } + + private static JsonTypeInfo GetTypeInfo(Type runtimeType, JsonSerializerOptions? options) + { + options ??= JsonSerializerOptions.s_defaultOptions; + options.RootBuiltInConvertersAndTypeInfoCreator(); + return options.GetOrAddClassForRootType(runtimeType); + } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Stream.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Stream.cs index e555cdde3395c..05ea4220a057d 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Stream.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Stream.cs @@ -34,9 +34,16 @@ public static partial class JsonSerializer CancellationToken cancellationToken = default) { if (utf8Json == null) + { throw new ArgumentNullException(nameof(utf8Json)); + } - return WriteAsyncCore(utf8Json, value, typeof(TValue), options, cancellationToken); + return SerializeAsync( + utf8Json, + value, + GetRuntimeType(value), + options, + cancellationToken); } /// @@ -70,24 +77,104 @@ public static Task SerializeAsync( throw new ArgumentNullException(nameof(utf8Json)); } - if (inputType == null) + return SerializeAsync( + utf8Json, + value!, + GetRuntimeTypeAndValidateInputType(value, inputType), + options, + cancellationToken); + } + + private static Task SerializeAsync( + Stream utf8Json, + in TValue value, + Type runtimeType, + JsonSerializerOptions? options, + CancellationToken cancellationToken) + { + JsonTypeInfo jsonTypeInfo = GetTypeInfo(runtimeType, options); + return WriteAsyncCore(utf8Json, value!, runtimeType, jsonTypeInfo, cancellationToken); + } + + /// + /// Convert the provided value to UTF-8 encoded JSON text and write it to the . + /// + /// A task that represents the asynchronous write operation. + /// The UTF-8 to write to. + /// The value to convert. + /// Metadata about the type to convert. + /// The which may be used to cancel the write operation. + /// + /// is . + /// + /// + /// There is no compatible + /// for or its serializable members. + /// + public static Task SerializeAsync(Stream utf8Json, TValue value, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken = default) + { + if (utf8Json == null) { - throw new ArgumentNullException(nameof(inputType)); + throw new ArgumentNullException(nameof(utf8Json)); } - if (value != null && !inputType.IsAssignableFrom(value.GetType())) + if (jsonTypeInfo == null) { - ThrowHelper.ThrowArgumentException_DeserializeWrongType(inputType, value); + throw new ArgumentNullException(nameof(jsonTypeInfo)); } - return WriteAsyncCore(utf8Json, value!, inputType, options, cancellationToken); + return WriteAsyncCore(utf8Json, value, typeof(TValue), jsonTypeInfo, cancellationToken); + } + + /// + /// Convert the provided value to UTF-8 encoded JSON text and write it to the . + /// + /// A task that represents the asynchronous write operation. + /// The UTF-8 to write to. + /// The value to convert. + /// The type of the to convert. + /// A metadata provider for serializable types. + /// The which may be used to cancel the write operation. + /// + /// is not compatible with . + /// + /// + /// or is . + /// + /// + /// There is no compatible + /// for or its serializable members. + /// + public static Task SerializeAsync( + Stream utf8Json, + object? value, + [DynamicallyAccessedMembers(MembersAccessedOnWrite)] Type inputType, + JsonSerializerContext context, + CancellationToken cancellationToken = default) + { + if (utf8Json == null) + { + throw new ArgumentNullException(nameof(utf8Json)); + } + + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + + return WriteAsyncCore( + utf8Json, + value!, + GetRuntimeTypeAndValidateInputType(value, inputType), + JsonHelpers.GetTypeInfo(context, inputType), + cancellationToken); } private static async Task WriteAsyncCore( Stream utf8Json, TValue value, Type inputType, - JsonSerializerOptions? options, + JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken) { // We flush the Stream when the buffer is >=90% of capacity. @@ -98,26 +185,14 @@ private static async Task WriteAsyncCore( // means the buffer may be expanded a maximum of 4 times: 1-(1\(2^4))==.9375. const float FlushThreshold = .9f; - if (options == null) - { - options = JsonSerializerOptions.s_defaultOptions; - } - - options.RootBuiltInConvertersAndTypeInfoCreator(); - + JsonSerializerOptions options = jsonTypeInfo.Options; JsonWriterOptions writerOptions = options.GetWriterOptions(); using (var bufferWriter = new PooledByteBufferWriter(options.DefaultBufferSize)) using (var writer = new Utf8JsonWriter(bufferWriter, writerOptions)) { - // We treat typeof(object) special and allow polymorphic behavior. - if (inputType == JsonTypeInfo.ObjectType && value != null) - { - inputType = value!.GetType(); - } - WriteStack state = new WriteStack { CancellationToken = cancellationToken }; - JsonConverter converterBase = state.Initialize(inputType, options, supportContinuation: true); + JsonConverter converter = state.Initialize(jsonTypeInfo, supportContinuation: true); bool isFinalBlock; @@ -129,7 +204,7 @@ private static async Task WriteAsyncCore( try { - isFinalBlock = WriteCore(converterBase, writer, value, options, ref state); + isFinalBlock = WriteCore(converter, writer, value, options, ref state); } finally { diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.String.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.String.cs index 8ba4701dab90a..9abceca6979f2 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.String.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.String.cs @@ -20,12 +20,12 @@ public static partial class JsonSerializer /// for or its serializable members. /// /// Using a is not as efficient as using UTF-8 - /// encoding since the implementation internally uses UTF-8. See also - /// and . + /// encoding since the implementation internally uses UTF-8. See also + /// and . /// public static string Serialize<[DynamicallyAccessedMembers(MembersAccessedOnWrite)] TValue>(TValue value, JsonSerializerOptions? options = null) { - return Serialize(value, typeof(TValue), options); + return Serialize(value, GetRuntimeType(value), options); } /// @@ -43,45 +43,26 @@ public static partial class JsonSerializer /// for or its serializable members. /// /// Using a is not as efficient as using UTF-8 - /// encoding since the implementation internally uses UTF-8. See also - /// and . + /// encoding since the implementation internally uses UTF-8. See also + /// and . /// public static string Serialize( object? value, [DynamicallyAccessedMembers(MembersAccessedOnWrite)] Type inputType, JsonSerializerOptions? options = null) { - if (inputType == null) - { - throw new ArgumentNullException(nameof(inputType)); - } - - if (value != null && !inputType.IsAssignableFrom(value.GetType())) - { - ThrowHelper.ThrowArgumentException_DeserializeWrongType(inputType, value); - } - - return Serialize(value, inputType, options); + return Serialize( + value, + GetRuntimeTypeAndValidateInputType(value, inputType), + options); } - private static string Serialize(in TValue value, Type inputType, JsonSerializerOptions? options) + private static string Serialize(in TValue value, Type runtimeType, JsonSerializerOptions? options) { - if (options == null) - { - options = JsonSerializerOptions.s_defaultOptions; - } - + options ??= JsonSerializerOptions.s_defaultOptions; options.RootBuiltInConvertersAndTypeInfoCreator(); - - using (var output = new PooledByteBufferWriter(options.DefaultBufferSize)) - { - using (var writer = new Utf8JsonWriter(output, options.GetWriterOptions())) - { - WriteCore(writer, value, inputType, options); - } - - return JsonReaderHelper.TranscodeHelper(output.WrittenMemory.Span); - } + JsonTypeInfo typeInfo = options.GetOrAddClassForRootType(runtimeType); + return SerializeUsingMetadata(value, typeInfo); } /// @@ -98,8 +79,8 @@ private static string Serialize(in TValue value, Type inputType, JsonSer /// is . /// /// Using a is not as efficient as using UTF-8 - /// encoding since the implementation internally uses UTF-8. See also - /// and . + /// encoding since the implementation internally uses UTF-8. See also + /// and . /// public static string Serialize(TValue value, JsonTypeInfo jsonTypeInfo) { @@ -112,38 +93,28 @@ public static string Serialize(TValue value, JsonTypeInfo jsonTy /// A representation of the value. /// The value to convert. /// The type of the to convert. - /// A metadata provider for serializable types. + /// A metadata provider for serializable types. /// /// There is no compatible /// for or its serializable members. /// /// /// The method of the provided - /// returns for the type to convert. + /// returns for the type to convert. /// /// Using a is not as efficient as using UTF-8 - /// encoding since the implementation internally uses UTF-8. See also - /// and . + /// encoding since the implementation internally uses UTF-8. See also + /// and . /// - public static string Serialize(object? value, Type inputType, JsonSerializerContext jsonSerializerContext) + public static string Serialize(object? value, Type inputType, JsonSerializerContext context) { - if (inputType == null) - { - throw new ArgumentNullException(nameof(inputType)); - } - - if (jsonSerializerContext == null) + if (context == null) { - throw new ArgumentNullException(nameof(jsonSerializerContext)); + throw new ArgumentNullException(nameof(context)); } - Type type = inputType == typeof(object) && value != null - ? value.GetType() - : inputType; - - return SerializeUsingMetadata( - value, - JsonHelpers.GetJsonTypeInfo(jsonSerializerContext, type)); + Type runtimeType = GetRuntimeTypeAndValidateInputType(value, inputType); + return SerializeUsingMetadata(value, JsonHelpers.GetTypeInfo(context, runtimeType)); } private static string SerializeUsingMetadata(in TValue value, JsonTypeInfo? jsonTypeInfo) @@ -153,17 +124,16 @@ private static string SerializeUsingMetadata(in TValue value, JsonTypeIn throw new ArgumentNullException(nameof(jsonTypeInfo)); } - JsonSerializerOptions options = jsonTypeInfo.Options; - WriteStack state = default; - state.Initialize(jsonTypeInfo, options, supportContinuation: false); + state.Initialize(jsonTypeInfo, supportContinuation: false); + + JsonSerializerOptions options = jsonTypeInfo.Options; using (var output = new PooledByteBufferWriter(options.DefaultBufferSize)) { using (var writer = new Utf8JsonWriter(output, options.GetWriterOptions())) { - JsonConverter? jsonConverter = jsonTypeInfo.PropertyInfoForTypeInfo.ConverterBase; - WriteCore(jsonConverter, writer, value, options, ref state); + SerializeUsingMetadata(writer, value, jsonTypeInfo); } return JsonReaderHelper.TranscodeHelper(output.WrittenMemory.Span); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Utf8JsonWriter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Utf8JsonWriter.cs index 6ffa8c6d32997..b8bc8c7b0a022 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Utf8JsonWriter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Utf8JsonWriter.cs @@ -1,9 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; namespace System.Text.Json { @@ -27,7 +27,7 @@ public static partial class JsonSerializer TValue value, JsonSerializerOptions? options = null) { - Serialize(writer, value, typeof(TValue), options); + Serialize(writer, value, GetRuntimeType(value), options); } /// @@ -53,34 +53,87 @@ public static void Serialize( [DynamicallyAccessedMembers(MembersAccessedOnWrite)] Type inputType, JsonSerializerOptions? options = null) { - if (inputType == null) - { - throw new ArgumentNullException(nameof(inputType)); - } + Serialize( + writer, + value, + GetRuntimeTypeAndValidateInputType(value, inputType), + options); + } - if (value != null && !inputType.IsAssignableFrom(value.GetType())) + private static void Serialize(Utf8JsonWriter writer, in TValue value, Type runtimeType, JsonSerializerOptions? options) + { + if (writer == null) { - ThrowHelper.ThrowArgumentException_DeserializeWrongType(inputType, value); + throw new ArgumentNullException(nameof(writer)); } - Serialize(writer, value, inputType, options); + JsonTypeInfo typeInfo = GetTypeInfo(runtimeType, options); + SerializeUsingMetadata(writer, value, typeInfo); } - private static void Serialize(Utf8JsonWriter writer, in TValue value, Type type, JsonSerializerOptions? options) + /// + /// Write one JSON value (including objects or arrays) to the provided writer. + /// + /// The writer to write. + /// The value to convert and write. + /// Metadata about the type to convert. + /// + /// or is . + /// + /// + /// There is no compatible + /// for or its serializable members. + /// + public static void Serialize(Utf8JsonWriter writer, TValue value, JsonTypeInfo jsonTypeInfo) { - if (options == null) + if (writer == null) + { + throw new ArgumentNullException(nameof(writer)); + } + + if (jsonTypeInfo == null) { - options = JsonSerializerOptions.s_defaultOptions; + throw new ArgumentNullException(nameof(jsonTypeInfo)); } - options.RootBuiltInConvertersAndTypeInfoCreator(); + SerializeUsingMetadata(writer, value, jsonTypeInfo); + } + /// + /// Write one JSON value (including objects or arrays) to the provided writer. + /// + /// + /// The value to convert and write. + /// The type of the to convert. + /// A metadata provider for serializable types. + /// + /// is not compatible with . + /// + /// + /// or is . + /// + /// + /// There is no compatible + /// for or its serializable members. + /// + /// + /// The method of the provided + /// returns for the type to convert. + /// + public static void Serialize(Utf8JsonWriter writer, object? value, Type inputType, JsonSerializerContext context) + { if (writer == null) { throw new ArgumentNullException(nameof(writer)); } - WriteCore(writer, value, type, options); + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + + Type runtimeType = GetRuntimeTypeAndValidateInputType(value, inputType); + SerializeUsingMetadata(writer, value, JsonHelpers.GetTypeInfo(context, runtimeType)); } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs index 769f9621cce7c..b31f07803a153 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs @@ -29,7 +29,7 @@ public sealed partial class JsonSerializerOptions internal JsonSerializerContext? _context; - private Func? _typeInfoCreationFunc = null!; + private static Func? _typeInfoCreationFunc = null!; // For any new option added, adding it to the options copied in the copy constructor below must be considered. diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfo.Cache.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfo.Cache.cs index e24a986d23af0..d70d628b5d670 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfo.Cache.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfo.Cache.cs @@ -581,7 +581,7 @@ internal void InitializeDeserializePropCache() InitializeSerializePropCache(); } - PropertyCache = new Dictionary(Options.PropertyNameCaseInsensitive + Dictionary propertyCache = new(Options.PropertyNameCaseInsensitive ? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal); @@ -589,11 +589,14 @@ internal void InitializeDeserializePropCache() { JsonPropertyInfo jsonPropertyInfo = PropertyCacheArray[i]; - if (!JsonHelpers.TryAdd(PropertyCache!, jsonPropertyInfo.NameAsString, jsonPropertyInfo)) + if (!JsonHelpers.TryAdd(propertyCache, jsonPropertyInfo.NameAsString, jsonPropertyInfo)) { ThrowHelper.ThrowInvalidOperationException_SerializerPropertyNameConflict(Type, jsonPropertyInfo); } } + + // Avoid threading issues by populating a local cache, and assigning it to the global cache after completion. + PropertyCache = propertyCache; } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/WriteStack.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/WriteStack.cs index 41ac243f19fe0..22f67983ec346 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/WriteStack.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/WriteStack.cs @@ -89,15 +89,17 @@ private void AddCurrent() public JsonConverter Initialize(Type type, JsonSerializerOptions options, bool supportContinuation) { JsonTypeInfo jsonTypeInfo = options.GetOrAddClassForRootType(type); - return Initialize(jsonTypeInfo, options, supportContinuation); + Debug.Assert(options == jsonTypeInfo.Options); + return Initialize(jsonTypeInfo, supportContinuation); } - internal JsonConverter Initialize(JsonTypeInfo jsonTypeInfo, JsonSerializerOptions options, bool supportContinuation) + internal JsonConverter Initialize(JsonTypeInfo jsonTypeInfo, bool supportContinuation) { Current.JsonTypeInfo = jsonTypeInfo; Current.DeclaredJsonPropertyInfo = jsonTypeInfo.PropertyInfoForTypeInfo; Current.NumberHandling = Current.DeclaredJsonPropertyInfo.NumberHandling; + JsonSerializerOptions options = jsonTypeInfo.Options; if (options.ReferenceHandlingStrategy != ReferenceHandlingStrategy.None) { Debug.Assert(options.ReferenceHandler != null); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs b/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs index 70f455dbe45fd..ab7cf89e8afb5 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs @@ -177,7 +177,7 @@ public static void ThrowInvalidOperationException_SerializerOptionsImmutable(Jso [MethodImpl(MethodImplOptions.NoInlining)] public static void ThrowInvalidOperationException_SerializerPropertyNameConflict(Type type, JsonPropertyInfo jsonPropertyInfo) { - throw new InvalidOperationException(SR.Format(SR.SerializerPropertyNameConflict, type, jsonPropertyInfo.MemberInfo?.Name)); + throw new InvalidOperationException(SR.Format(SR.SerializerPropertyNameConflict, type, jsonPropertyInfo.ClrName)); } [DoesNotReturn] diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/DeserializationWrapper.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/DeserializationWrapper.cs index 1c84c0bd698de..790d0f115db81 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/DeserializationWrapper.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/DeserializationWrapper.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.IO; +using System.Text.Json.Serialization.Metadata; using System.Threading.Tasks; namespace System.Text.Json.Serialization.Tests @@ -15,12 +16,18 @@ public abstract class DeserializationWrapper public static DeserializationWrapper StringDeserializer => new StringDeserializerWrapper(); public static DeserializationWrapper StreamDeserializer => new StreamDeserializerWrapper(); - public static DeserializationWrapper SpanDeserializer => new SpanDesearializationWrapper(); + public static DeserializationWrapper SpanDeserializer => new SpanDeserializerWrapper(); + + public static DeserializationWrapper ReaderDeserializer => new ReaderDeserializerWrapper(); protected internal abstract Task DeserializeWrapper(string json, JsonSerializerOptions options = null); protected internal abstract Task DeserializeWrapper(string json, Type type, JsonSerializerOptions options = null); + protected internal abstract Task DeserializeWrapper(string json, JsonTypeInfo jsonTypeInfo); + + protected internal abstract Task DeserializeWrapper(string json, Type type, JsonSerializerContext context); + private class StringDeserializerWrapper : DeserializationWrapper { protected internal override Task DeserializeWrapper(string json, JsonSerializerOptions options = null) @@ -32,38 +39,54 @@ protected internal override Task DeserializeWrapper(string json, Type ty { return Task.FromResult(JsonSerializer.Deserialize(json, type, options)); } + + protected internal override Task DeserializeWrapper(string json, JsonTypeInfo jsonTypeInfo) + { + return Task.FromResult(JsonSerializer.Deserialize(json, jsonTypeInfo)); + } + + protected internal override Task DeserializeWrapper(string json, Type type, JsonSerializerContext context) + { + return Task.FromResult(JsonSerializer.Deserialize(json, type, context)); + } } private class StreamDeserializerWrapper : DeserializationWrapper { protected internal override async Task DeserializeWrapper(string json, JsonSerializerOptions options = null) { - if (options == null) + using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(json))) { - options = _optionsWithSmallBuffer; + return await JsonSerializer.DeserializeAsync(stream, options ?? _optionsWithSmallBuffer); } + } + protected internal override async Task DeserializeWrapper(string json, Type type, JsonSerializerOptions options = null) + { using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(json))) { - return await JsonSerializer.DeserializeAsync(stream, options); + return await JsonSerializer.DeserializeAsync(stream, type, options ?? _optionsWithSmallBuffer); } } - protected internal override async Task DeserializeWrapper(string json, Type type, JsonSerializerOptions options = null) + protected internal override async Task DeserializeWrapper(string json, JsonTypeInfo jsonTypeInfo) { - if (options == null) + using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(json))) { - options = _optionsWithSmallBuffer; + return await JsonSerializer.DeserializeAsync(stream, jsonTypeInfo); } + } + protected internal override async Task DeserializeWrapper(string json, Type type, JsonSerializerContext context) + { using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(json))) { - return await JsonSerializer.DeserializeAsync(stream, type, options); + return await JsonSerializer.DeserializeAsync(stream, type, context); } } } - private class SpanDesearializationWrapper : DeserializationWrapper + private class SpanDeserializerWrapper : DeserializationWrapper { protected internal override Task DeserializeWrapper(string json, JsonSerializerOptions options = null) { @@ -74,6 +97,43 @@ protected internal override Task DeserializeWrapper(string json, Type ty { return Task.FromResult(JsonSerializer.Deserialize(json.AsSpan(), type, options)); } + + protected internal override Task DeserializeWrapper(string json, JsonTypeInfo jsonTypeInfo) + { + return Task.FromResult(JsonSerializer.Deserialize(json.AsSpan(), jsonTypeInfo)); + } + + protected internal override Task DeserializeWrapper(string json, Type type, JsonSerializerContext context) + { + return Task.FromResult(JsonSerializer.Deserialize(json.AsSpan(), type, context)); + } + } + + private class ReaderDeserializerWrapper : DeserializationWrapper + { + protected internal override Task DeserializeWrapper(string json, JsonSerializerOptions options = null) + { + Utf8JsonReader reader = new(Encoding.UTF8.GetBytes(json)); + return Task.FromResult(JsonSerializer.Deserialize(ref reader, options)); + } + + protected internal override Task DeserializeWrapper(string json, Type type, JsonSerializerOptions options = null) + { + Utf8JsonReader reader = new(Encoding.UTF8.GetBytes(json)); + return Task.FromResult(JsonSerializer.Deserialize(ref reader, type, options)); + } + + protected internal override Task DeserializeWrapper(string json, JsonTypeInfo jsonTypeInfo) + { + Utf8JsonReader reader = new(Encoding.UTF8.GetBytes(json)); + return Task.FromResult(JsonSerializer.Deserialize(ref reader, jsonTypeInfo)); + } + + protected internal override Task DeserializeWrapper(string json, Type type, JsonSerializerContext context) + { + Utf8JsonReader reader = new(Encoding.UTF8.GetBytes(json)); + return Task.FromResult(JsonSerializer.Deserialize(ref reader, type, context)); + } } } } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/DateTimeOffset.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/DateTimeOffset.cs new file mode 100644 index 0000000000000..c11ab0b179f92 --- /dev/null +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/DateTimeOffset.cs @@ -0,0 +1,33 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; + +namespace System.Text.Json.Tests.Serialization +{ + internal partial class JsonContext : JsonSerializerContext + { + private JsonTypeInfo _DateTimeOffset; + public JsonTypeInfo DateTimeOffset + { + get + { + if (_DateTimeOffset == null) + { + JsonConverter customConverter; + if (Options.Converters.Count > 0 && (customConverter = GetRuntimeProvidedCustomConverter(typeof(DateTimeOffset))) != null) + { + _DateTimeOffset = JsonMetadataServices.CreateValueInfo(Options, customConverter); + } + else + { + _DateTimeOffset = JsonMetadataServices.CreateValueInfo(Options, JsonMetadataServices.DateTimeOffsetConverter); + } + } + + return _DateTimeOffset; + } + } + } +} diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/Dictionary.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/Dictionary.cs new file mode 100644 index 0000000000000..781e0fa409d6b --- /dev/null +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/Dictionary.cs @@ -0,0 +1,34 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; + +namespace System.Text.Json.Tests.Serialization +{ + internal partial class JsonContext : JsonSerializerContext + { + private JsonTypeInfo> _Dictionary; + public JsonTypeInfo> Dictionary + { + get + { + if (_Dictionary == null) + { + JsonConverter customConverter; + if (Options.Converters.Count > 0 && (customConverter = GetRuntimeProvidedCustomConverter(typeof(Dictionary))) != null) + { + _Dictionary = JsonMetadataServices.CreateValueInfo>(Options, customConverter); + } + else + { + _Dictionary = JsonMetadataServices.CreateDictionaryInfo, string, HighLowTemps>(Options, () => new Dictionary(), this.String, this.HighLowTemps, default); + } + } + + return _Dictionary; + } + } + } +} diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/HighLowTemps.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/HighLowTemps.cs new file mode 100644 index 0000000000000..68fff77f0ef17 --- /dev/null +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/HighLowTemps.cs @@ -0,0 +1,77 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; + +namespace System.Text.Json.Tests.Serialization +{ + internal partial class JsonContext : JsonSerializerContext + { + private JsonTypeInfo _HighLowTemps; + public JsonTypeInfo HighLowTemps + { + get + { + if (_HighLowTemps == null) + { + JsonConverter customConverter; + if (Options.Converters.Count > 0 && (customConverter = GetRuntimeProvidedCustomConverter(typeof(HighLowTemps))) != null) + { + _HighLowTemps = JsonMetadataServices.CreateValueInfo(Options, customConverter); + } + else + { + JsonTypeInfo objectInfo = JsonMetadataServices.CreateObjectInfo(); + _HighLowTemps = objectInfo; + + JsonMetadataServices.InitializeObjectInfo( + objectInfo, + Options, + createObjectFunc: static () => new HighLowTemps(), + HighLowTempsPropInitFunc, + default); + } + } + + return _HighLowTemps; + } + } + + private static JsonPropertyInfo[] HighLowTempsPropInitFunc(JsonSerializerContext context) + { + JsonContext jsonContext = (JsonContext)context; + JsonSerializerOptions options = context.Options; + + JsonPropertyInfo[] properties = new JsonPropertyInfo[2]; + + properties[0] = JsonMetadataServices.CreatePropertyInfo( + options, + isProperty: true, + declaringType: typeof(HighLowTemps), + propertyTypeInfo: jsonContext.Int32, + converter: null, + getter: static (obj) => { return ((HighLowTemps)obj).High; }, + setter: static (obj, value) => { ((HighLowTemps)obj).High = value; }, + ignoreCondition: default, + numberHandling: default, + propertyName: "High", + jsonPropertyName: null); + + properties[1] = JsonMetadataServices.CreatePropertyInfo( + options, + isProperty: true, + declaringType: typeof(HighLowTemps), + propertyTypeInfo: jsonContext.Int32, + converter: null, + getter: static (obj) => { return ((HighLowTemps)obj).Low; }, + setter: static (obj, value) => { ((HighLowTemps)obj).Low = value; }, + ignoreCondition: default, + numberHandling: default, + propertyName: "Low", + jsonPropertyName: null); + + return properties; + } + } +} diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/Int32.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/Int32.cs new file mode 100644 index 0000000000000..4afacd38ce761 --- /dev/null +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/Int32.cs @@ -0,0 +1,33 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; + +namespace System.Text.Json.Tests.Serialization +{ + internal partial class JsonContext : JsonSerializerContext + { + private JsonTypeInfo _Int32; + public JsonTypeInfo Int32 + { + get + { + if (_Int32 == null) + { + JsonConverter customConverter; + if (Options.Converters.Count > 0 && (customConverter = GetRuntimeProvidedCustomConverter(typeof(int))) != null) + { + _Int32 = JsonMetadataServices.CreateValueInfo(Options, customConverter); + } + else + { + _Int32 = JsonMetadataServices.CreateValueInfo(Options, JsonMetadataServices.Int32Converter); + } + } + + return _Int32; + } + } + } +} diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/JsonContext.GetJsonTypeInfo.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/JsonContext.GetJsonTypeInfo.cs new file mode 100644 index 0000000000000..19ae4904f19ec --- /dev/null +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/JsonContext.GetJsonTypeInfo.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; + +namespace System.Text.Json.Tests.Serialization +{ + internal partial class JsonContext : JsonSerializerContext + { + public override JsonTypeInfo GetTypeInfo(System.Type type) + { + if (type == typeof(WeatherForecastWithPOCOs)) + { + return this.WeatherForecastWithPOCOs; + } + + return null!; + } + } +} diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/JsonContext.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/JsonContext.cs new file mode 100644 index 0000000000000..f3172684bb6fa --- /dev/null +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/JsonContext.cs @@ -0,0 +1,48 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace System.Text.Json.Tests.Serialization +{ + internal partial class JsonContext : JsonSerializerContext + { + private static JsonContext s_default; + public static JsonContext Default => s_default ??= new JsonContext(new JsonSerializerOptions()); + + public JsonContext() : base(null) + { + } + + public JsonContext(JsonSerializerOptions options) : base(options) + { + } + + private JsonConverter GetRuntimeProvidedCustomConverter(System.Type type) + { + IList converters = Options.Converters; + + for (int i = 0; i < converters.Count; i++) + { + JsonConverter converter = converters[i]; + + if (converter.CanConvert(type)) + { + if (converter is JsonConverterFactory factory) + { + converter = factory.CreateConverter(type, Options); + if (converter == null || converter is JsonConverterFactory) + { + throw new System.InvalidOperationException($"The converter '{factory.GetType()}' cannot return null or a JsonConverterFactory instance."); + } + } + + return converter; + } + } + + return null; + } + } +} diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/List.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/List.cs new file mode 100644 index 0000000000000..24a2e95c3105a --- /dev/null +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/List.cs @@ -0,0 +1,34 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; + +namespace System.Text.Json.Tests.Serialization +{ + internal partial class JsonContext : JsonSerializerContext + { + private JsonTypeInfo> _ListSystemDateTimeOffset; + public JsonTypeInfo> ListSystemDateTimeOffset + { + get + { + if (_ListSystemDateTimeOffset == null) + { + JsonConverter customConverter; + if (Options.Converters.Count > 0 && (customConverter = GetRuntimeProvidedCustomConverter(typeof(List))) != null) + { + _ListSystemDateTimeOffset = JsonMetadataServices.CreateValueInfo>(Options, customConverter); + } + else + { + _ListSystemDateTimeOffset = JsonMetadataServices.CreateListInfo, DateTimeOffset>(Options, () => new List(), this.DateTimeOffset, default); + } + } + + return _ListSystemDateTimeOffset; + } + } + } +} diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/String.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/String.cs new file mode 100644 index 0000000000000..19f7cfb3db696 --- /dev/null +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/String.cs @@ -0,0 +1,33 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Text.Json.Serialization.Metadata; +using System.Text.Json.Serialization; + +namespace System.Text.Json.Tests.Serialization +{ + internal partial class JsonContext : JsonSerializerContext + { + private JsonTypeInfo _String; + public JsonTypeInfo String + { + get + { + if (_String == null) + { + JsonConverter customConverter; + if (Options.Converters.Count > 0 && (customConverter = GetRuntimeProvidedCustomConverter(typeof(string))) != null) + { + _String = JsonMetadataServices.CreateValueInfo(Options, customConverter); + } + else + { + _String = JsonMetadataServices.CreateValueInfo (Options, JsonMetadataServices.StringConverter); + } + } + + return _String; + } + } + } +} diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/StringArray.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/StringArray.cs new file mode 100644 index 0000000000000..21445e3dc50d4 --- /dev/null +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/StringArray.cs @@ -0,0 +1,33 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Text.Json.Serialization.Metadata; +using System.Text.Json.Serialization; + +namespace System.Text.Json.Tests.Serialization +{ + internal partial class JsonContext : JsonSerializerContext + { + private JsonTypeInfo _StringArray; + public JsonTypeInfo StringArray + { + get + { + if (_StringArray == null) + { + JsonConverter customConverter; + if (Options.Converters.Count > 0 && (customConverter = GetRuntimeProvidedCustomConverter(typeof(string[]))) != null) + { + _StringArray = JsonMetadataServices.CreateValueInfo(Options, customConverter); + } + else + { + _StringArray = JsonMetadataServices.CreateArrayInfo(Options, this.String, default); + } + } + + return _StringArray; + } + } + } +} diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/WeatherForecastWithPOCOs.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/WeatherForecastWithPOCOs.cs new file mode 100644 index 0000000000000..e402afb16ba92 --- /dev/null +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/WeatherForecastWithPOCOs.cs @@ -0,0 +1,142 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; + +namespace System.Text.Json.Tests.Serialization +{ + internal partial class JsonContext : JsonSerializerContext + { + private JsonTypeInfo _WeatherForecastWithPOCOs; + public JsonTypeInfo WeatherForecastWithPOCOs + { + get + { + if (_WeatherForecastWithPOCOs == null) + { + JsonConverter customConverter; + if (Options.Converters.Count > 0 && (customConverter = GetRuntimeProvidedCustomConverter(typeof(WeatherForecastWithPOCOs))) != null) + { + _WeatherForecastWithPOCOs = JsonMetadataServices.CreateValueInfo(Options, customConverter); + } + else + { + JsonTypeInfo objectInfo = JsonMetadataServices.CreateObjectInfo(); + _WeatherForecastWithPOCOs = objectInfo; + + JsonMetadataServices.InitializeObjectInfo( + objectInfo, + Options, + createObjectFunc: static () => new WeatherForecastWithPOCOs(), + WeatherForecastWithPOCOsPropInitFunc, + default); + } + } + + return _WeatherForecastWithPOCOs; + } + } + + private static JsonPropertyInfo[] WeatherForecastWithPOCOsPropInitFunc(JsonSerializerContext context) + { + JsonContext jsonContext = (JsonContext)context; + JsonSerializerOptions options = context.Options; + + JsonPropertyInfo[] properties = new JsonPropertyInfo[7]; + + properties[0] = JsonMetadataServices.CreatePropertyInfo( + options, + isProperty: true, + declaringType: typeof(WeatherForecastWithPOCOs), + propertyTypeInfo: jsonContext.DateTimeOffset, + converter: null, + getter: static (obj) => { return ((WeatherForecastWithPOCOs)obj).Date; }, + setter: static (obj, value) => { ((WeatherForecastWithPOCOs)obj).Date = value; }, + ignoreCondition: default, + numberHandling: default, + propertyName: "Date", + jsonPropertyName: null); + + properties[1] = JsonMetadataServices.CreatePropertyInfo( + options, + isProperty: true, + declaringType: typeof(WeatherForecastWithPOCOs), + propertyTypeInfo: jsonContext.Int32, + converter: null, + getter: static (obj) => { return ((WeatherForecastWithPOCOs)obj).TemperatureCelsius; }, + setter: static (obj, value) => { ((WeatherForecastWithPOCOs)obj).TemperatureCelsius = value; }, + ignoreCondition: default, + numberHandling: default, + propertyName: "TemperatureCelsius", + jsonPropertyName: null); + + properties[2] = JsonMetadataServices.CreatePropertyInfo( + options, + isProperty: true, + declaringType: typeof(WeatherForecastWithPOCOs), + propertyTypeInfo: jsonContext.String, + converter: null, + getter: static (obj) => { return ((WeatherForecastWithPOCOs)obj).Summary; }, + setter: static (obj, value) => { ((WeatherForecastWithPOCOs)obj).Summary = value; }, + ignoreCondition: default, + numberHandling: default, + propertyName: "Summary", + jsonPropertyName: null); + + properties[3] = JsonMetadataServices.CreatePropertyInfo( + options, + isProperty: true, + declaringType: typeof(WeatherForecastWithPOCOs), + propertyTypeInfo: jsonContext.ListSystemDateTimeOffset, + converter: null, + getter: static (obj) => { return ((WeatherForecastWithPOCOs)obj).DatesAvailable; }, + setter: static (obj, value) => { ((WeatherForecastWithPOCOs)obj).DatesAvailable = value; }, + ignoreCondition: default, + numberHandling: default, + propertyName: "DatesAvailable", + jsonPropertyName: null); + + properties[4] = JsonMetadataServices.CreatePropertyInfo( + options, + isProperty: true, + declaringType: typeof(WeatherForecastWithPOCOs), + propertyTypeInfo: jsonContext.Dictionary, + converter: null, + getter: static (obj) => { return ((WeatherForecastWithPOCOs)obj).TemperatureRanges; }, + setter: static (obj, value) => { ((WeatherForecastWithPOCOs)obj).TemperatureRanges = value; }, + ignoreCondition: default, + numberHandling: default, + propertyName: "TemperatureRanges", + jsonPropertyName: null); + + properties[5] = JsonMetadataServices.CreatePropertyInfo( + options, + isProperty: true, + declaringType: typeof(WeatherForecastWithPOCOs), + propertyTypeInfo: jsonContext.StringArray, + converter: null, + getter: static (obj) => { return ((WeatherForecastWithPOCOs)obj).SummaryWords; }, + setter: static (obj, value) => { ((WeatherForecastWithPOCOs)obj).SummaryWords = value; }, + ignoreCondition: default, + numberHandling: default, + propertyName: "SummaryWords", + jsonPropertyName: null); + + properties[6] = JsonMetadataServices.CreatePropertyInfo( + options, + isProperty: false, + declaringType: typeof(WeatherForecastWithPOCOs), + propertyTypeInfo: jsonContext.String, + converter: null, + getter: static (obj) => { return ((WeatherForecastWithPOCOs)obj).SummaryField; }, + setter: static (obj, value) => { ((WeatherForecastWithPOCOs)obj).SummaryField = value; }, + ignoreCondition: default, + numberHandling: default, + propertyName: "SummaryField", + jsonPropertyName: null); + + return properties; + } + } +} diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataServicesTests/MetadataServicesTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/MetadataTests.JsonMetadataServices.cs similarity index 96% rename from src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataServicesTests/MetadataServicesTests.cs rename to src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/MetadataTests.JsonMetadataServices.cs index 0e0818222cdb4..9d93c2d8720e3 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataServicesTests/MetadataServicesTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/MetadataTests.JsonMetadataServices.cs @@ -10,10 +10,10 @@ namespace System.Text.Json.Tests.Serialization { - public static partial class MetadataServicesTests + public abstract partial class MetadataTests { [Fact] - public static void CreatePropertyInfo() + public void CreatePropertyInfo() { JsonSerializerOptions options = new(); @@ -102,7 +102,7 @@ private class MyClass { } private class MyDerivedClass : MyClass { } [Fact] - public static void CreateObjectInfo() + public void CreateObjectInfo() { JsonSerializerOptions options = new(); @@ -146,7 +146,7 @@ public static void CreateObjectInfo() } [Fact] - public static void CreateValueInfo() + public void CreateValueInfo() { JsonSerializerOptions options = new(); @@ -162,7 +162,7 @@ public static void CreateValueInfo() } [Fact] - public static void CreateArrayInfo() + public void CreateArrayInfo() { JsonSerializerOptions options = new(); @@ -182,7 +182,7 @@ public static void CreateArrayInfo() } [Fact] - public static void CreateListInfo() + public void CreateListInfo() { JsonSerializerOptions options = new(); @@ -204,7 +204,7 @@ public static void CreateListInfo() } [Fact] - public static void CreateDictionaryInfo() + public void CreateDictionaryInfo() { JsonSerializerOptions options = new(); @@ -249,7 +249,7 @@ private class DerivedClassConverter : JsonConverter } [Fact] - public static void GetEnumConverter() + public void GetEnumConverter() { JsonConverter converter = JsonMetadataServices.GetEnumConverter(new JsonSerializerOptions()); Assert.NotNull(converter); @@ -257,7 +257,7 @@ public static void GetEnumConverter() } [Fact] - public static void GetNullableConverter() + public void GetNullableConverter() { JsonSerializerOptions options = new(); JsonConverter enumConverter = JsonMetadataServices.GetEnumConverter(options); diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/MetadataTests.JsonSerializer.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/MetadataTests.JsonSerializer.cs new file mode 100644 index 0000000000000..40137337b65f1 --- /dev/null +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/MetadataTests.JsonSerializer.cs @@ -0,0 +1,86 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Xunit; + +namespace System.Text.Json.Tests.Serialization +{ + public abstract partial class MetadataTests + { + [Fact] + public async Task RoundTripSerializerOverloads() + { + WeatherForecastWithPOCOs expected = CreateWeatherForecastWithPOCOs(); + string json = await Serializer.SerializeWrapper(expected, JsonContext.Default.WeatherForecastWithPOCOs); + WeatherForecastWithPOCOs actual = await Deserializer.DeserializeWrapper(json, JsonContext.Default.WeatherForecastWithPOCOs); + VerifyWeatherForecastWithPOCOs(expected, actual); + + json = await Serializer.SerializeWrapper(actual, typeof(WeatherForecastWithPOCOs), JsonContext.Default); + actual = (WeatherForecastWithPOCOs)await Deserializer.DeserializeWrapper(json, typeof(WeatherForecastWithPOCOs), JsonContext.Default); + VerifyWeatherForecastWithPOCOs(expected, actual); + } + + private static WeatherForecastWithPOCOs CreateWeatherForecastWithPOCOs() + { + return new WeatherForecastWithPOCOs + { + Date = DateTime.Parse("2019-08-01T00:00:00-07:00"), + TemperatureCelsius = 25, + Summary = "Hot", + DatesAvailable = new List + { + DateTimeOffset.Parse("2019-08-01T00:00:00-07:00"), + DateTimeOffset.Parse("2019-08-02T00:00:00-07:00"), + }, + TemperatureRanges = new Dictionary { + { + "Cold", + new HighLowTemps + { + High = 20, + Low = -10, + } + }, + { + "Hot", + new HighLowTemps + { + High = 60, + Low = 20, + } + }, + }, + SummaryWords = new string[] { "Cool", "Windy", "Humid" }, + }; + } + + private static void VerifyWeatherForecastWithPOCOs(WeatherForecastWithPOCOs expected, WeatherForecastWithPOCOs obj) + { + Assert.Equal(expected.Date, obj.Date); + Assert.Equal(expected.TemperatureCelsius, obj.TemperatureCelsius); + Assert.Equal(expected.Summary, obj.Summary); + Assert.Equal(expected.DatesAvailable.Count, obj.DatesAvailable.Count); + for (int i = 0; i < expected.DatesAvailable.Count; i++) + { + Assert.Equal(expected.DatesAvailable[i], obj.DatesAvailable[i]); + } + List> expectedTemperatureRanges = expected.TemperatureRanges.OrderBy(kv => kv.Key).ToList(); + List> objTemperatureRanges = obj.TemperatureRanges.OrderBy(kv => kv.Key).ToList(); + Assert.Equal(expectedTemperatureRanges.Count, objTemperatureRanges.Count); + for (int i = 0; i < expectedTemperatureRanges.Count; i++) + { + Assert.Equal(expectedTemperatureRanges[i].Key, objTemperatureRanges[i].Key); + Assert.Equal(expectedTemperatureRanges[i].Value.Low, objTemperatureRanges[i].Value.Low); + Assert.Equal(expectedTemperatureRanges[i].Value.High, objTemperatureRanges[i].Value.High); + } + Assert.Equal(expected.SummaryWords.Length, obj.SummaryWords.Length); + for (int i = 0; i < expected.SummaryWords.Length; i++) + { + Assert.Equal(expected.SummaryWords[i], obj.SummaryWords[i]); + } + } + } +} diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataServicesTests/MetadataServicesTests.Options.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/MetadataTests.Options.cs similarity index 92% rename from src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataServicesTests/MetadataServicesTests.Options.cs rename to src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/MetadataTests.Options.cs index cf750f487c97a..285eb397fa3d9 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataServicesTests/MetadataServicesTests.Options.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/MetadataTests.Options.cs @@ -8,10 +8,10 @@ namespace System.Text.Json.Tests.Serialization { - public static partial class MetadataServicesTests + public abstract partial class MetadataTests { [Fact] - public static void JsonSerializerContextCtor() + public void JsonSerializerContextCtor() { // Pass no options. MyJsonContext context = new(); @@ -25,7 +25,7 @@ public static void JsonSerializerContextCtor() } [Fact] - public static void AddContext() + public void AddContext() { JsonSerializerOptions options = new(); options.AddContext(); @@ -44,7 +44,7 @@ private static void CauseInvalidOperationException(Action action) } [Fact] - public static void AddContextOverwritesOptionsForFreshContext() + public void AddContextOverwritesOptionsForFreshContext() { // Context binds with options when instantiated with parameterless ctor. MyJsonContextThatSetsOptionsInParameterlessCtor context = new(); @@ -61,7 +61,7 @@ public static void AddContextOverwritesOptionsForFreshContext() } [Fact] - public static void AlreadyBindedOptions() + public void AlreadyBindedOptions() { // Bind the options. JsonSerializerOptions options = new(); @@ -72,7 +72,7 @@ public static void AlreadyBindedOptions() } [Fact] - public static void OptionsImmutableAfterBinding() + public void OptionsImmutableAfterBinding() { // Bind via AddContext JsonSerializerOptions options = new(); diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/MetadataTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/MetadataTests.cs new file mode 100644 index 0000000000000..2587c571d324a --- /dev/null +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/MetadataTests.cs @@ -0,0 +1,58 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Text.Json.Serialization.Tests; + +namespace System.Text.Json.Tests.Serialization +{ + public sealed class MetadataTests_Span : MetadataTests + { + public MetadataTests_Span() : base(SerializationWrapper.SpanSerializer, DeserializationWrapper.SpanDeserializer) { } + } + + public sealed class MetadataTests_String : MetadataTests + { + public MetadataTests_String() : base(SerializationWrapper.StringSerializer, DeserializationWrapper.StringDeserializer) { } + } + + public sealed class MetadataTests_Stream : MetadataTests + { + public MetadataTests_Stream() : base(SerializationWrapper.StreamSerializer, DeserializationWrapper.StreamDeserializer) { } + } + + public sealed class MetadataTests_LowLevel : MetadataTests + { + public MetadataTests_LowLevel() : base(SerializationWrapper.WriterSerializer, DeserializationWrapper.ReaderDeserializer) { } + } + + public abstract partial class MetadataTests + { + protected SerializationWrapper Serializer { get; } + + protected DeserializationWrapper Deserializer { get; } + + public MetadataTests(SerializationWrapper serializer, DeserializationWrapper deserializer) + { + Serializer = serializer; + Deserializer = deserializer; + } + } + + internal class WeatherForecastWithPOCOs + { + public DateTimeOffset Date { get; set; } + public int TemperatureCelsius { get; set; } + public string Summary { get; set; } + public string SummaryField; + public List DatesAvailable { get; set; } + public Dictionary TemperatureRanges { get; set; } + public string[] SummaryWords { get; set; } + } + + public class HighLowTemps + { + public int High { get; set; } + public int Low { get; set; } + } +} diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/SerializationWrapper.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/SerializationWrapper.cs index 9b933260f27a8..02c5952b4eae1 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/SerializationWrapper.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/SerializationWrapper.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.IO; +using System.Text.Json.Serialization.Metadata; using System.Threading.Tasks; namespace System.Text.Json.Serialization.Tests @@ -23,6 +24,10 @@ public abstract class SerializationWrapper protected internal abstract Task SerializeWrapper(T value, JsonSerializerOptions options = null); + protected internal abstract Task SerializeWrapper(object value, Type inputType, JsonSerializerContext context); + + protected internal abstract Task SerializeWrapper(T value, JsonTypeInfo jsonTypeInfo); + private class SpanSerializerWrapper : SerializationWrapper { @@ -37,6 +42,18 @@ protected internal override Task SerializeWrapper(T value, JsonSerial byte[] result = JsonSerializer.SerializeToUtf8Bytes(value, options); return Task.FromResult(Encoding.UTF8.GetString(result)); } + + protected internal override Task SerializeWrapper(object value, Type inputType, JsonSerializerContext context) + { + byte[] result = JsonSerializer.SerializeToUtf8Bytes(value, inputType, context); + return Task.FromResult(Encoding.UTF8.GetString(result)); + } + + protected internal override Task SerializeWrapper(T value, JsonTypeInfo jsonTypeInfo) + { + byte[] result = JsonSerializer.SerializeToUtf8Bytes(value, jsonTypeInfo); + return Task.FromResult(Encoding.UTF8.GetString(result)); + } } private class StringSerializerWrapper : SerializationWrapper @@ -50,6 +67,16 @@ protected internal override Task SerializeWrapper(T value, JsonSerial { return Task.FromResult(JsonSerializer.Serialize(value, options)); } + + protected internal override Task SerializeWrapper(object value, Type inputType, JsonSerializerContext context) + { + return Task.FromResult(JsonSerializer.Serialize(value, inputType, context)); + } + + protected internal override Task SerializeWrapper(T value, JsonTypeInfo jsonTypeInfo) + { + return Task.FromResult(JsonSerializer.Serialize(value, jsonTypeInfo)); + } } private class StreamSerializerWrapper : SerializationWrapper @@ -67,6 +94,20 @@ protected internal override async Task SerializeWrapper(T value, Json await JsonSerializer.SerializeAsync(stream, value, options); return Encoding.UTF8.GetString(stream.ToArray()); } + + protected internal override async Task SerializeWrapper(object value, Type inputType, JsonSerializerContext context) + { + using var stream = new MemoryStream(); + await JsonSerializer.SerializeAsync(stream, value, inputType, context); + return Encoding.UTF8.GetString(stream.ToArray()); + } + + protected internal override async Task SerializeWrapper(T value, JsonTypeInfo jsonTypeInfo) + { + using var stream = new MemoryStream(); + await JsonSerializer.SerializeAsync(stream, value, jsonTypeInfo); + return Encoding.UTF8.GetString(stream.ToArray()); + } } private class StreamSerializerWrapperWithSmallBuffer : StreamSerializerWrapper @@ -104,6 +145,22 @@ protected internal override Task SerializeWrapper(T value, JsonSerial JsonSerializer.Serialize(writer, value, options); return Task.FromResult(Encoding.UTF8.GetString(stream.ToArray())); } + + protected internal override Task SerializeWrapper(object value, Type inputType, JsonSerializerContext context) + { + using MemoryStream stream = new MemoryStream(); + using var writer = new Utf8JsonWriter(stream); + JsonSerializer.Serialize(writer, value, inputType, context); + return Task.FromResult(Encoding.UTF8.GetString(stream.ToArray())); + } + + protected internal override Task SerializeWrapper(T value, JsonTypeInfo jsonTypeInfo) + { + using MemoryStream stream = new MemoryStream(); + using var writer = new Utf8JsonWriter(stream); + JsonSerializer.Serialize(writer, value, jsonTypeInfo); + return Task.FromResult(Encoding.UTF8.GetString(stream.ToArray())); + } } } } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/System.Text.Json.Tests.csproj b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/System.Text.Json.Tests.csproj index 1bdb9fbf82fee..dd2b6c8aa39a0 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/System.Text.Json.Tests.csproj +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/System.Text.Json.Tests.csproj @@ -113,8 +113,20 @@ - - + + + + + + + + + + + + + + From d80df60e288f2ebc6433e9b44cd09e100e31cd66 Mon Sep 17 00:00:00 2001 From: Layomi Akinrinade Date: Tue, 20 Apr 2021 12:22:02 -0700 Subject: [PATCH 2/2] Address review feedback --- .../JsonContext/JsonContext.cs | 2 +- .../FunctionalTests/JsonContext/Person.cs | 8 ++--- .../System.Text.Json/ref/System.Text.Json.cs | 2 +- .../JsonSerializer.Write.ByteArray.cs | 3 +- .../JsonSerializer.Write.Helpers.cs | 2 +- .../JsonSerializer.Write.Stream.cs | 33 +++++++++---------- .../JsonSerializer.Write.String.cs | 22 ++++++------- .../JsonSerializer.Write.Utf8JsonWriter.cs | 26 +++++++-------- .../Serialization/JsonSerializerOptions.cs | 2 +- .../MetadataTests/JsonContext/HighLowTemps.cs | 4 +-- .../JsonContext/WeatherForecastWithPOCOs.cs | 14 ++++---- 11 files changed, 58 insertions(+), 60 deletions(-) diff --git a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/JsonContext/JsonContext.cs b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/JsonContext/JsonContext.cs index bb8268da02029..452644e2aa572 100644 --- a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/JsonContext/JsonContext.cs +++ b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/JsonContext/JsonContext.cs @@ -21,7 +21,7 @@ public JsonContext(JsonSerializerOptions options) : base(options) { } - private JsonConverter GetRuntimeProvidedCustomConverter(System.Type type) + private JsonConverter GetRuntimeProvidedCustomConverter(Type type) { IList converters = Options.Converters; diff --git a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/JsonContext/Person.cs b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/JsonContext/Person.cs index b53eeb900bcb8..f383d17a7f04d 100644 --- a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/JsonContext/Person.cs +++ b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/JsonContext/Person.cs @@ -55,7 +55,7 @@ private static JsonPropertyInfo[] PersonPropInitFunc(JsonSerializerContext conte setter: static (obj, value) => { ((Person)obj).Age = value; }, ignoreCondition: default, numberHandling: default, - propertyName: "Age", + propertyName: nameof(Tests.Person.Age), jsonPropertyName: null); properties[1] = JsonMetadataServices.CreatePropertyInfo( @@ -68,7 +68,7 @@ private static JsonPropertyInfo[] PersonPropInitFunc(JsonSerializerContext conte setter: static (obj, value) => { ((Person)obj).Name = value; }, ignoreCondition: default, numberHandling: default, - propertyName: "Name", + propertyName: nameof(Tests.Person.Name), jsonPropertyName: null); properties[2] = JsonMetadataServices.CreatePropertyInfo( @@ -81,7 +81,7 @@ private static JsonPropertyInfo[] PersonPropInitFunc(JsonSerializerContext conte setter: static (obj, value) => { ((Person)obj).Parent = value; }, ignoreCondition: default, numberHandling: default, - propertyName: "Parent", + propertyName: nameof(Tests.Person.Parent), jsonPropertyName: null); properties[3] = JsonMetadataServices.CreatePropertyInfo( @@ -94,7 +94,7 @@ private static JsonPropertyInfo[] PersonPropInitFunc(JsonSerializerContext conte setter: static (obj, value) => { ((Person)obj).PlaceOfBirth = value; }, ignoreCondition: default, numberHandling: default, - propertyName: "PlaceOfBirth", + propertyName: nameof(Tests.Person.PlaceOfBirth), jsonPropertyName: null); return properties; diff --git a/src/libraries/System.Text.Json/ref/System.Text.Json.cs b/src/libraries/System.Text.Json/ref/System.Text.Json.cs index 1c71f86aab725..48b3cf84494bd 100644 --- a/src/libraries/System.Text.Json/ref/System.Text.Json.cs +++ b/src/libraries/System.Text.Json/ref/System.Text.Json.cs @@ -645,7 +645,7 @@ public override void WriteTo(System.Text.Json.Utf8JsonWriter writer, System.Text } public abstract partial class JsonValue : System.Text.Json.Node.JsonNode { - internal JsonValue() { } + private protected JsonValue(System.Text.Json.Node.JsonNodeOptions? options = default(System.Text.Json.Node.JsonNodeOptions?)) { throw null; } public static System.Text.Json.Node.JsonValue? Create(T? value, System.Text.Json.Node.JsonNodeOptions? options = default(System.Text.Json.Node.JsonNodeOptions?)) { throw null; } public abstract bool TryGetValue<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] T>([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out T? value); } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.ByteArray.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.ByteArray.cs index ab67afbe0422b..73035cdf77a8e 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.ByteArray.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.ByteArray.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Text.Json.Serialization; using System.Text.Json.Serialization.Metadata; @@ -124,7 +123,7 @@ private static byte[] WriteCoreBytes(in TValue value, JsonTypeInfo jsonT { using (var writer = new Utf8JsonWriter(output, options.GetWriterOptions())) { - SerializeUsingMetadata(writer, value, jsonTypeInfo); + WriteUsingMetadata(writer, value, jsonTypeInfo); } return output.WrittenMemory.ToArray(); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Helpers.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Helpers.cs index bf4dea2837284..abbe1b5841615 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Helpers.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Helpers.cs @@ -39,7 +39,7 @@ private static bool WriteCore( return success; } - private static void SerializeUsingMetadata(Utf8JsonWriter writer, in TValue value, JsonTypeInfo jsonTypeInfo) + private static void WriteUsingMetadata(Utf8JsonWriter writer, in TValue value, JsonTypeInfo jsonTypeInfo) { WriteStack state = default; state.Initialize(jsonTypeInfo, supportContinuation: false); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Stream.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Stream.cs index 05ea4220a057d..5a42d6e6dbf6c 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Stream.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Stream.cs @@ -38,7 +38,7 @@ public static partial class JsonSerializer throw new ArgumentNullException(nameof(utf8Json)); } - return SerializeAsync( + return WriteAsync( utf8Json, value, GetRuntimeType(value), @@ -77,7 +77,7 @@ public static Task SerializeAsync( throw new ArgumentNullException(nameof(utf8Json)); } - return SerializeAsync( + return WriteAsync( utf8Json, value!, GetRuntimeTypeAndValidateInputType(value, inputType), @@ -85,17 +85,6 @@ public static Task SerializeAsync( cancellationToken); } - private static Task SerializeAsync( - Stream utf8Json, - in TValue value, - Type runtimeType, - JsonSerializerOptions? options, - CancellationToken cancellationToken) - { - JsonTypeInfo jsonTypeInfo = GetTypeInfo(runtimeType, options); - return WriteAsyncCore(utf8Json, value!, runtimeType, jsonTypeInfo, cancellationToken); - } - /// /// Convert the provided value to UTF-8 encoded JSON text and write it to the . /// @@ -123,7 +112,7 @@ public static Task SerializeAsync(Stream utf8Json, TValue value, JsonTyp throw new ArgumentNullException(nameof(jsonTypeInfo)); } - return WriteAsyncCore(utf8Json, value, typeof(TValue), jsonTypeInfo, cancellationToken); + return WriteAsyncCore(utf8Json, value, jsonTypeInfo, cancellationToken); } /// @@ -162,18 +151,28 @@ public static Task SerializeAsync( throw new ArgumentNullException(nameof(context)); } + Type runtimeType = GetRuntimeTypeAndValidateInputType(value, inputType); return WriteAsyncCore( utf8Json, value!, - GetRuntimeTypeAndValidateInputType(value, inputType), - JsonHelpers.GetTypeInfo(context, inputType), + JsonHelpers.GetTypeInfo(context, runtimeType), cancellationToken); } + private static Task WriteAsync( + Stream utf8Json, + in TValue value, + Type runtimeType, + JsonSerializerOptions? options, + CancellationToken cancellationToken) + { + JsonTypeInfo jsonTypeInfo = GetTypeInfo(runtimeType, options); + return WriteAsyncCore(utf8Json, value!, jsonTypeInfo, cancellationToken); + } + private static async Task WriteAsyncCore( Stream utf8Json, TValue value, - Type inputType, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken) { diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.String.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.String.cs index 9abceca6979f2..01caa984a2d55 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.String.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.String.cs @@ -25,7 +25,7 @@ public static partial class JsonSerializer /// public static string Serialize<[DynamicallyAccessedMembers(MembersAccessedOnWrite)] TValue>(TValue value, JsonSerializerOptions? options = null) { - return Serialize(value, GetRuntimeType(value), options); + return Write(value, GetRuntimeType(value), options); } /// @@ -51,20 +51,12 @@ public static string Serialize( [DynamicallyAccessedMembers(MembersAccessedOnWrite)] Type inputType, JsonSerializerOptions? options = null) { - return Serialize( + return Write( value, GetRuntimeTypeAndValidateInputType(value, inputType), options); } - private static string Serialize(in TValue value, Type runtimeType, JsonSerializerOptions? options) - { - options ??= JsonSerializerOptions.s_defaultOptions; - options.RootBuiltInConvertersAndTypeInfoCreator(); - JsonTypeInfo typeInfo = options.GetOrAddClassForRootType(runtimeType); - return SerializeUsingMetadata(value, typeInfo); - } - /// /// Convert the provided value into a . /// @@ -117,6 +109,14 @@ public static string Serialize(object? value, Type inputType, JsonSerializerCont return SerializeUsingMetadata(value, JsonHelpers.GetTypeInfo(context, runtimeType)); } + private static string Write(in TValue value, Type runtimeType, JsonSerializerOptions? options) + { + options ??= JsonSerializerOptions.s_defaultOptions; + options.RootBuiltInConvertersAndTypeInfoCreator(); + JsonTypeInfo typeInfo = options.GetOrAddClassForRootType(runtimeType); + return SerializeUsingMetadata(value, typeInfo); + } + private static string SerializeUsingMetadata(in TValue value, JsonTypeInfo? jsonTypeInfo) { if (jsonTypeInfo == null) @@ -133,7 +133,7 @@ private static string SerializeUsingMetadata(in TValue value, JsonTypeIn { using (var writer = new Utf8JsonWriter(output, options.GetWriterOptions())) { - SerializeUsingMetadata(writer, value, jsonTypeInfo); + WriteUsingMetadata(writer, value, jsonTypeInfo); } return JsonReaderHelper.TranscodeHelper(output.WrittenMemory.Span); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Utf8JsonWriter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Utf8JsonWriter.cs index b8bc8c7b0a022..566684774b3c3 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Utf8JsonWriter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Utf8JsonWriter.cs @@ -60,17 +60,6 @@ public static void Serialize( options); } - private static void Serialize(Utf8JsonWriter writer, in TValue value, Type runtimeType, JsonSerializerOptions? options) - { - if (writer == null) - { - throw new ArgumentNullException(nameof(writer)); - } - - JsonTypeInfo typeInfo = GetTypeInfo(runtimeType, options); - SerializeUsingMetadata(writer, value, typeInfo); - } - /// /// Write one JSON value (including objects or arrays) to the provided writer. /// @@ -96,7 +85,7 @@ public static void Serialize(Utf8JsonWriter writer, TValue value, JsonTy throw new ArgumentNullException(nameof(jsonTypeInfo)); } - SerializeUsingMetadata(writer, value, jsonTypeInfo); + WriteUsingMetadata(writer, value, jsonTypeInfo); } /// @@ -133,7 +122,18 @@ public static void Serialize(Utf8JsonWriter writer, object? value, Type inputTyp } Type runtimeType = GetRuntimeTypeAndValidateInputType(value, inputType); - SerializeUsingMetadata(writer, value, JsonHelpers.GetTypeInfo(context, runtimeType)); + WriteUsingMetadata(writer, value, JsonHelpers.GetTypeInfo(context, runtimeType)); + } + + private static void Serialize(Utf8JsonWriter writer, in TValue value, Type runtimeType, JsonSerializerOptions? options) + { + if (writer == null) + { + throw new ArgumentNullException(nameof(writer)); + } + + JsonTypeInfo typeInfo = GetTypeInfo(runtimeType, options); + WriteUsingMetadata(writer, value, typeInfo); } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs index b31f07803a153..adec4350cad2c 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs @@ -29,7 +29,7 @@ public sealed partial class JsonSerializerOptions internal JsonSerializerContext? _context; - private static Func? _typeInfoCreationFunc = null!; + private Func? _typeInfoCreationFunc; // For any new option added, adding it to the options copied in the copy constructor below must be considered. diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/HighLowTemps.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/HighLowTemps.cs index 68fff77f0ef17..c477b08bb2c38 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/HighLowTemps.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/HighLowTemps.cs @@ -55,7 +55,7 @@ private static JsonPropertyInfo[] HighLowTempsPropInitFunc(JsonSerializerContext setter: static (obj, value) => { ((HighLowTemps)obj).High = value; }, ignoreCondition: default, numberHandling: default, - propertyName: "High", + propertyName: nameof(Serialization.HighLowTemps.High), jsonPropertyName: null); properties[1] = JsonMetadataServices.CreatePropertyInfo( @@ -68,7 +68,7 @@ private static JsonPropertyInfo[] HighLowTempsPropInitFunc(JsonSerializerContext setter: static (obj, value) => { ((HighLowTemps)obj).Low = value; }, ignoreCondition: default, numberHandling: default, - propertyName: "Low", + propertyName: nameof(Serialization.HighLowTemps.Low), jsonPropertyName: null); return properties; diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/WeatherForecastWithPOCOs.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/WeatherForecastWithPOCOs.cs index e402afb16ba92..62d85930d74fb 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/WeatherForecastWithPOCOs.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonContext/WeatherForecastWithPOCOs.cs @@ -55,7 +55,7 @@ private static JsonPropertyInfo[] WeatherForecastWithPOCOsPropInitFunc(JsonSeria setter: static (obj, value) => { ((WeatherForecastWithPOCOs)obj).Date = value; }, ignoreCondition: default, numberHandling: default, - propertyName: "Date", + propertyName: nameof(Serialization.WeatherForecastWithPOCOs.Date), jsonPropertyName: null); properties[1] = JsonMetadataServices.CreatePropertyInfo( @@ -68,7 +68,7 @@ private static JsonPropertyInfo[] WeatherForecastWithPOCOsPropInitFunc(JsonSeria setter: static (obj, value) => { ((WeatherForecastWithPOCOs)obj).TemperatureCelsius = value; }, ignoreCondition: default, numberHandling: default, - propertyName: "TemperatureCelsius", + propertyName: nameof(Serialization.WeatherForecastWithPOCOs.TemperatureCelsius), jsonPropertyName: null); properties[2] = JsonMetadataServices.CreatePropertyInfo( @@ -81,7 +81,7 @@ private static JsonPropertyInfo[] WeatherForecastWithPOCOsPropInitFunc(JsonSeria setter: static (obj, value) => { ((WeatherForecastWithPOCOs)obj).Summary = value; }, ignoreCondition: default, numberHandling: default, - propertyName: "Summary", + propertyName: nameof(Serialization.WeatherForecastWithPOCOs.Summary), jsonPropertyName: null); properties[3] = JsonMetadataServices.CreatePropertyInfo( @@ -94,7 +94,7 @@ private static JsonPropertyInfo[] WeatherForecastWithPOCOsPropInitFunc(JsonSeria setter: static (obj, value) => { ((WeatherForecastWithPOCOs)obj).DatesAvailable = value; }, ignoreCondition: default, numberHandling: default, - propertyName: "DatesAvailable", + propertyName: nameof(Serialization.WeatherForecastWithPOCOs.DatesAvailable), jsonPropertyName: null); properties[4] = JsonMetadataServices.CreatePropertyInfo( @@ -107,7 +107,7 @@ private static JsonPropertyInfo[] WeatherForecastWithPOCOsPropInitFunc(JsonSeria setter: static (obj, value) => { ((WeatherForecastWithPOCOs)obj).TemperatureRanges = value; }, ignoreCondition: default, numberHandling: default, - propertyName: "TemperatureRanges", + propertyName: nameof(Serialization.WeatherForecastWithPOCOs.TemperatureRanges), jsonPropertyName: null); properties[5] = JsonMetadataServices.CreatePropertyInfo( @@ -120,7 +120,7 @@ private static JsonPropertyInfo[] WeatherForecastWithPOCOsPropInitFunc(JsonSeria setter: static (obj, value) => { ((WeatherForecastWithPOCOs)obj).SummaryWords = value; }, ignoreCondition: default, numberHandling: default, - propertyName: "SummaryWords", + propertyName: nameof(Serialization.WeatherForecastWithPOCOs.SummaryWords), jsonPropertyName: null); properties[6] = JsonMetadataServices.CreatePropertyInfo( @@ -133,7 +133,7 @@ private static JsonPropertyInfo[] WeatherForecastWithPOCOsPropInitFunc(JsonSeria setter: static (obj, value) => { ((WeatherForecastWithPOCOs)obj).SummaryField = value; }, ignoreCondition: default, numberHandling: default, - propertyName: "SummaryField", + propertyName: nameof(Serialization.WeatherForecastWithPOCOs.SummaryField), jsonPropertyName: null); return properties;