diff --git a/src/libraries/Directory.Build.targets b/src/libraries/Directory.Build.targets index cb644757a2d95..348a71ba8da89 100644 --- a/src/libraries/Directory.Build.targets +++ b/src/libraries/Directory.Build.targets @@ -7,6 +7,18 @@ $(TestStrongNameKeyId) + + + + true + true + true + + @@ -47,14 +59,6 @@ --> $(WarningsAsErrors.Replace('NU1605', '')) - - true - true - true false diff --git a/src/libraries/System.Text.Json/src/System.Text.Json.csproj b/src/libraries/System.Text.Json/src/System.Text.Json.csproj index 5765b6cdbee86..3e867457e45ba 100644 --- a/src/libraries/System.Text.Json/src/System.Text.Json.csproj +++ b/src/libraries/System.Text.Json/src/System.Text.Json.csproj @@ -8,6 +8,8 @@ CS8969 true true + true + 1 Provides high-performance and low-allocating types that serialize objects to JavaScript Object Notation (JSON) text and deserialize JSON text to objects, with UTF-8 support built-in. Also provides types to read and write JSON text encoded as UTF-8, and to create an in-memory document object model (DOM), that is read-only, for random access of the JSON elements within a structured view of the data. The System.Text.Json library is built-in as part of the shared framework in .NET Runtime. The package can be installed when you need to use it in other target frameworks. diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonArray.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonArray.cs index 8dc0924ad36e6..32096972d6df7 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonArray.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonArray.cs @@ -174,13 +174,7 @@ internal JsonArray(JsonElement element, JsonNodeOptions? options = null) : base( [RequiresDynamicCode(JsonValue.CreateDynamicCodeMessage)] public void Add(T? value) { - JsonNode? nodeToAdd = value switch - { - null => null, - JsonNode node => node, - _ => JsonValue.Create(value, Options) - }; - + JsonNode? nodeToAdd = ConvertFromValue(value, Options); Add(nodeToAdd); } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonNode.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonNode.cs index a06fc47cfc1c4..43b6048828a84 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonNode.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonNode.cs @@ -3,6 +3,8 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; +using System.Text.Json.Serialization.Converters; +using System.Text.Json.Serialization.Metadata; namespace System.Text.Json.Nodes { @@ -316,17 +318,16 @@ public static bool DeepEquals(JsonNode? node1, JsonNode? node2) [RequiresDynamicCode(JsonValue.CreateDynamicCodeMessage)] public void ReplaceWith(T value) { + JsonNode? node; switch (_parent) { - case null: - return; case JsonObject jsonObject: - JsonValue? jsonValue = JsonValue.Create(value); - jsonObject.SetItem(GetPropertyName(), jsonValue); + node = ConvertFromValue(value); + jsonObject.SetItem(GetPropertyName(), node); return; case JsonArray jsonArray: - JsonValue? jValue = JsonValue.Create(value); - jsonArray.SetItem(GetElementIndex(), jValue); + node = ConvertFromValue(value); + jsonArray.SetItem(GetElementIndex(), node); return; } } @@ -351,5 +352,33 @@ internal void AssignParent(JsonNode parent) Parent = parent; } + + /// + /// Adaptation of the equivalent JsonValue.Create factory method extended + /// to support arbitrary and values. + /// TODO consider making public cf. https://github.com/dotnet/runtime/issues/70427 + /// + [RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)] + [RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)] + internal static JsonNode? ConvertFromValue(T? value, JsonNodeOptions? options = null) + { + if (value is null) + { + return null; + } + + if (value is JsonNode node) + { + return node; + } + + if (value is JsonElement element) + { + return JsonNodeConverter.Create(element, options); + } + + var jsonTypeInfo = (JsonTypeInfo)JsonSerializerOptions.Default.GetTypeInfo(typeof(T)); + return new JsonValueCustomized(value, jsonTypeInfo, options); + } } } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonNode/JsonArrayTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonNode/JsonArrayTests.cs index 8f115d44b211f..ef51703958151 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonNode/JsonArrayTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonNode/JsonArrayTests.cs @@ -680,5 +680,74 @@ public static void ReplaceWith() Assert.Null(jValue.Parent); Assert.Equal("[5]", jArray.ToJsonString()); } + + [Theory] + [InlineData("null")] + [InlineData("1")] + [InlineData("false")] + [InlineData("\"str\"")] + [InlineData("""{"test":"hello world"}""")] + [InlineData("[1,2,3]")] + public static void AddJsonElement(string json) + { + // Regression test for https://github.com/dotnet/runtime/issues/94842 + using var jdoc = JsonDocument.Parse(json); + var array = new JsonArray(); + + array.Add(jdoc.RootElement); + + JsonNode arrayElement = Assert.Single(array); + switch (jdoc.RootElement.ValueKind) + { + case JsonValueKind.Object: + Assert.IsAssignableFrom(arrayElement); + break; + case JsonValueKind.Array: + Assert.IsAssignableFrom(arrayElement); + break; + case JsonValueKind.Null: + Assert.Null(arrayElement); + break; + default: + Assert.IsAssignableFrom(arrayElement); + break; + } + Assert.Equal($"[{json}]", array.ToJsonString()); + } + + [Theory] + [InlineData("null")] + [InlineData("1")] + [InlineData("false")] + [InlineData("\"str\"")] + [InlineData("""{"test":"hello world"}""")] + [InlineData("[1,2,3]")] + public static void ReplaceWithJsonElement(string json) + { + // Regression test for https://github.com/dotnet/runtime/issues/94842 + using var jdoc = JsonDocument.Parse(json); + var array = new JsonArray { 1 }; + + array[0].ReplaceWith(jdoc.RootElement); + + JsonNode arrayElement = Assert.Single(array); + switch (jdoc.RootElement.ValueKind) + { + case JsonValueKind.Object: + Assert.IsAssignableFrom(arrayElement); + break; + case JsonValueKind.Array: + Assert.IsAssignableFrom(arrayElement); + break; + case JsonValueKind.Null: + Assert.Null(arrayElement); + break; + default: + Assert.IsAssignableFrom(arrayElement); + break; + } + + Assert.Equal($"[{json}]", array.ToJsonString()); + } } }