From 190acf9728fd06e7299d8586e06e13892ed9764d Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Thu, 13 May 2021 13:29:32 -0500 Subject: [PATCH 1/3] JsonNode linker-safe improvements --- .../System.Text.Json/ref/System.Text.Json.cs | 50 ++- .../src/System.Text.Json.csproj | 1 + .../src/System/Text/Json/Nodes/JsonArray.cs | 2 +- .../Text/Json/Nodes/JsonNode.Operators.cs | 66 ++-- .../src/System/Text/Json/Nodes/JsonNode.cs | 2 +- .../Json/Nodes/JsonValue.CreateOverloads.cs | 324 ++++++++++++++++++ .../src/System/Text/Json/Nodes/JsonValue.cs | 55 ++- .../System/Text/Json/Nodes/JsonValueOfT.cs | 58 +++- .../Converters/Node/JsonNodeConverter.cs | 16 +- .../JsonNode/JsonValueTests.cs | 9 + 10 files changed, 528 insertions(+), 55 deletions(-) create mode 100644 src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValue.CreateOverloads.cs 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 a709ae3fd6abc..44e108135c00c 100644 --- a/src/libraries/System.Text.Json/ref/System.Text.Json.cs +++ b/src/libraries/System.Text.Json/ref/System.Text.Json.cs @@ -518,7 +518,7 @@ public JsonArray(params System.Text.Json.Nodes.JsonNode?[] items) { } public int Count { get { throw null; } } bool System.Collections.Generic.ICollection.IsReadOnly { get { throw null; } } public void Add(System.Text.Json.Nodes.JsonNode? item) { } - public void Add(T? value) { } + public void Add<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] T>(T? value) { } public void Clear() { } public bool Contains(System.Text.Json.Nodes.JsonNode? item) { throw null; } public static System.Text.Json.Nodes.JsonArray? Create(System.Text.Json.JsonElement element, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } @@ -543,7 +543,7 @@ internal JsonNode() { } public System.Text.Json.Nodes.JsonObject AsObject() { throw null; } public System.Text.Json.Nodes.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 virtual TValue GetValue() { throw null; } public static explicit operator bool (System.Text.Json.Nodes.JsonNode value) { throw null; } public static explicit operator byte (System.Text.Json.Nodes.JsonNode value) { throw null; } public static explicit operator char (System.Text.Json.Nodes.JsonNode value) { throw null; } @@ -666,7 +666,51 @@ public override void WriteTo(System.Text.Json.Utf8JsonWriter writer, System.Text public abstract partial class JsonValue : System.Text.Json.Nodes.JsonNode { private protected JsonValue(System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } - public static System.Text.Json.Nodes.JsonValue? Create(T? value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } + public static System.Text.Json.Nodes.JsonValue Create(bool value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } + public static System.Text.Json.Nodes.JsonValue Create(byte value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } + public static System.Text.Json.Nodes.JsonValue Create(char value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } + public static System.Text.Json.Nodes.JsonValue Create(System.DateTime value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } + public static System.Text.Json.Nodes.JsonValue Create(System.DateTimeOffset value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } + public static System.Text.Json.Nodes.JsonValue Create(decimal value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } + public static System.Text.Json.Nodes.JsonValue Create(double value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } + public static System.Text.Json.Nodes.JsonValue Create(System.Guid value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } + public static System.Text.Json.Nodes.JsonValue Create(short value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } + public static System.Text.Json.Nodes.JsonValue Create(int value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } + public static System.Text.Json.Nodes.JsonValue Create(long value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } + public static System.Text.Json.Nodes.JsonValue? Create(bool? value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } + public static System.Text.Json.Nodes.JsonValue? Create(byte? value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } + public static System.Text.Json.Nodes.JsonValue? Create(char? value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } + public static System.Text.Json.Nodes.JsonValue? Create(System.DateTimeOffset? value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } + public static System.Text.Json.Nodes.JsonValue? Create(System.DateTime? value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } + public static System.Text.Json.Nodes.JsonValue? Create(decimal? value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } + public static System.Text.Json.Nodes.JsonValue? Create(double? value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } + public static System.Text.Json.Nodes.JsonValue? Create(System.Guid? value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } + public static System.Text.Json.Nodes.JsonValue? Create(short? value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } + public static System.Text.Json.Nodes.JsonValue? Create(int? value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } + public static System.Text.Json.Nodes.JsonValue? Create(long? value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } + [System.CLSCompliantAttribute(false)] + public static System.Text.Json.Nodes.JsonValue? Create(sbyte? value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } + public static System.Text.Json.Nodes.JsonValue? Create(float? value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } + public static System.Text.Json.Nodes.JsonValue? Create(System.Text.Json.JsonElement? value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } + [System.CLSCompliantAttribute(false)] + public static System.Text.Json.Nodes.JsonValue? Create(ushort? value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } + [System.CLSCompliantAttribute(false)] + public static System.Text.Json.Nodes.JsonValue? Create(uint? value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } + [System.CLSCompliantAttribute(false)] + public static System.Text.Json.Nodes.JsonValue? Create(ulong? value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } + [System.CLSCompliantAttribute(false)] + public static System.Text.Json.Nodes.JsonValue Create(sbyte value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } + public static System.Text.Json.Nodes.JsonValue Create(float value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } + public static System.Text.Json.Nodes.JsonValue? Create(string? value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } + public static System.Text.Json.Nodes.JsonValue? Create(System.Text.Json.JsonElement value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } + [System.CLSCompliantAttribute(false)] + public static System.Text.Json.Nodes.JsonValue Create(ushort value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } + [System.CLSCompliantAttribute(false)] + public static System.Text.Json.Nodes.JsonValue Create(uint value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } + [System.CLSCompliantAttribute(false)] + public static System.Text.Json.Nodes.JsonValue Create(ulong value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } + public static System.Text.Json.Nodes.JsonValue? Create(T? value, System.Text.Json.Serialization.Metadata.JsonTypeInfo jsonTypeInfo, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } + public static System.Text.Json.Nodes.JsonValue? Create<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] T>(T? value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } public abstract bool TryGetValue([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out T? value); } } 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 1d5c0eb83d53c..4f0e103254645 100644 --- a/src/libraries/System.Text.Json/src/System.Text.Json.csproj +++ b/src/libraries/System.Text.Json/src/System.Text.Json.csproj @@ -60,6 +60,7 @@ + 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 c43ee004e5efe..4ed453aaf67a5 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 @@ -98,7 +98,7 @@ internal JsonArray (JsonElement element, JsonNodeOptions? options = null) : base /// /// The object to be added to the end of the . /// - public void Add(T? value) + public void Add<[DynamicallyAccessedMembers(JsonHelpers.MembersAccessedOnRead)] T>(T? value) { if (value == null) { diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonNode.Operators.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonNode.Operators.cs index 959c4d8cde56c..60474365e6303 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonNode.Operators.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonNode.Operators.cs @@ -9,207 +9,207 @@ public partial class JsonNode /// Defines an implicit conversion of a given to a . /// /// A to implicitly convert. - public static implicit operator JsonNode(bool value) => new JsonValue(value); + public static implicit operator JsonNode(bool value) => JsonValue.Create(value); /// /// Defines an implicit conversion of a given to a . /// /// A to implicitly convert. - public static implicit operator JsonNode?(bool? value) => value.HasValue ? new JsonValue(value.Value) : null; + public static implicit operator JsonNode?(bool? value) => JsonValue.Create(value); /// /// Defines an implicit conversion of a given to a . /// /// A to implicitly convert. - public static implicit operator JsonNode(byte value) => new JsonValue(value); + public static implicit operator JsonNode(byte value) => JsonValue.Create(value); /// /// Defines an implicit conversion of a given to a . /// /// A to implicitly convert. - public static implicit operator JsonNode?(byte? value) => value.HasValue ? new JsonValue(value.Value) : null; + public static implicit operator JsonNode?(byte? value) => JsonValue.Create(value); /// /// Defines an implicit conversion of a given to a . /// /// A to implicitly convert. - public static implicit operator JsonNode(char value) => new JsonValue(value); + public static implicit operator JsonNode(char value) => JsonValue.Create(value); /// /// Defines an implicit conversion of a given to a . /// /// A to implicitly convert. - public static implicit operator JsonNode?(char? value) => value.HasValue ? new JsonValue(value.Value) : null; + public static implicit operator JsonNode?(char? value) => JsonValue.Create(value); /// /// Defines an implicit conversion of a given to a . /// /// A to implicitly convert. - public static implicit operator JsonNode(DateTime value) => new JsonValue(value); + public static implicit operator JsonNode(DateTime value) => JsonValue.Create(value); /// /// Defines an implicit conversion of a given to a . /// /// A to implicitly convert. - public static implicit operator JsonNode?(DateTime? value) => value.HasValue ? new JsonValue(value.Value) : null; + public static implicit operator JsonNode?(DateTime? value) => JsonValue.Create(value); /// /// Defines an implicit conversion of a given to a . /// /// A to implicitly convert. - public static implicit operator JsonNode(DateTimeOffset value) => new JsonValue(value); + public static implicit operator JsonNode(DateTimeOffset value) => JsonValue.Create(value); /// /// Defines an implicit conversion of a given to a . /// /// A to implicitly convert. - public static implicit operator JsonNode?(DateTimeOffset? value) => value.HasValue ? new JsonValue(value.Value) : null; + public static implicit operator JsonNode?(DateTimeOffset? value) => JsonValue.Create(value); /// /// Defines an implicit conversion of a given to a . /// /// A to implicitly convert. - public static implicit operator JsonNode(decimal value) => new JsonValue(value); + public static implicit operator JsonNode(decimal value) => JsonValue.Create(value); /// /// Defines an implicit conversion of a given to a . /// /// A to implicitly convert. - public static implicit operator JsonNode?(decimal? value) => value.HasValue ? new JsonValue(value.Value) : null; + public static implicit operator JsonNode?(decimal? value) => JsonValue.Create(value); /// /// Defines an implicit conversion of a given to a . /// /// A to implicitly convert. - public static implicit operator JsonNode(double value) => new JsonValue(value); + public static implicit operator JsonNode(double value) => JsonValue.Create(value); /// /// Defines an implicit conversion of a given to a . /// /// A to implicitly convert. - public static implicit operator JsonNode?(double? value) => value.HasValue ? new JsonValue(value.Value) : null; + public static implicit operator JsonNode?(double? value) => JsonValue.Create(value); /// /// Defines an implicit conversion of a given to a . /// /// A to implicitly convert. - public static implicit operator JsonNode(Guid value) => new JsonValue(value); + public static implicit operator JsonNode(Guid value) => JsonValue.Create(value); /// /// Defines an implicit conversion of a given to a . /// /// A to implicitly convert. - public static implicit operator JsonNode?(Guid? value) => value.HasValue ? new JsonValue(value.Value) : null; + public static implicit operator JsonNode?(Guid? value) => JsonValue.Create(value); /// /// Defines an implicit conversion of a given to a . /// /// A to implicitly convert. - public static implicit operator JsonNode(short value) => new JsonValue(value); + public static implicit operator JsonNode(short value) => JsonValue.Create(value); /// /// Defines an implicit conversion of a given to a . /// /// A to implicitly convert. - public static implicit operator JsonNode?(short? value) => value.HasValue ? new JsonValue(value.Value) : null; + public static implicit operator JsonNode?(short? value) => JsonValue.Create(value); /// /// Defines an implicit conversion of a given to a . /// /// A to implicitly convert. - public static implicit operator JsonNode(int value) => new JsonValue(value); + public static implicit operator JsonNode(int value) => JsonValue.Create(value); /// /// Defines an implicit conversion of a given to a . /// /// A to implicitly convert. - public static implicit operator JsonNode?(int? value) => value.HasValue ? new JsonValue(value.Value) : null; + public static implicit operator JsonNode?(int? value) => JsonValue.Create(value); /// /// Defines an implicit conversion of a given to a . /// /// A to implicitly convert. - public static implicit operator JsonNode(long value) => new JsonValue(value); + public static implicit operator JsonNode(long value) => JsonValue.Create(value); /// /// Defines an implicit conversion of a given to a . /// /// A to implicitly convert. - public static implicit operator JsonNode?(long? value) => value.HasValue ? new JsonValue(value.Value) : null; + public static implicit operator JsonNode?(long? value) => JsonValue.Create(value); /// /// Defines an implicit conversion of a given to a . /// /// A to implicitly convert. [System.CLSCompliantAttribute(false)] - public static implicit operator JsonNode(sbyte value) => new JsonValue(value); + public static implicit operator JsonNode(sbyte value) => JsonValue.Create(value); /// /// Defines an implicit conversion of a given to a . /// /// A to implicitly convert. [System.CLSCompliantAttribute(false)] - public static implicit operator JsonNode?(sbyte? value) => value.HasValue ? new JsonValue(value.Value) : null; + public static implicit operator JsonNode?(sbyte? value) => JsonValue.Create(value); /// /// Defines an implicit conversion of a given to a . /// /// A to implicitly convert. - public static implicit operator JsonNode(float value) => new JsonValue(value); + public static implicit operator JsonNode(float value) => JsonValue.Create(value); /// /// Defines an implicit conversion of a given to a . /// /// A to implicitly convert. - public static implicit operator JsonNode?(float? value) => value.HasValue ? new JsonValue(value.Value) : null; + public static implicit operator JsonNode?(float? value) => JsonValue.Create(value); /// /// Defines an implicit conversion of a given to a . /// /// A to implicitly convert. - public static implicit operator JsonNode?(string? value) => (value == null ? null : new JsonValue(value)); + public static implicit operator JsonNode?(string? value) => JsonValue.Create(value); /// /// Defines an implicit conversion of a given to a . /// /// A to implicitly convert. [System.CLSCompliantAttribute(false)] - public static implicit operator JsonNode(ushort value) => new JsonValue(value); + public static implicit operator JsonNode(ushort value) => JsonValue.Create(value); /// /// Defines an implicit conversion of a given to a . /// /// A to implicitly convert. [System.CLSCompliantAttribute(false)] - public static implicit operator JsonNode?(ushort? value) => value.HasValue ? new JsonValue(value.Value) : null; + public static implicit operator JsonNode?(ushort? value) => JsonValue.Create(value); /// /// Defines an implicit conversion of a given to a . /// /// A to implicitly convert. [System.CLSCompliantAttribute(false)] - public static implicit operator JsonNode(uint value) => new JsonValue(value); + public static implicit operator JsonNode(uint value) => JsonValue.Create(value); /// /// Defines an implicit conversion of a given to a . /// /// A to implicitly convert. [System.CLSCompliantAttribute(false)] - public static implicit operator JsonNode?(uint? value) => value.HasValue ? new JsonValue(value.Value) : null; + public static implicit operator JsonNode?(uint? value) => JsonValue.Create(value); /// /// Defines an implicit conversion of a given to a . /// /// A to implicitly convert. [System.CLSCompliantAttribute(false)] - public static implicit operator JsonNode(ulong value) => new JsonValue(value); + public static implicit operator JsonNode(ulong value) => JsonValue.Create(value); /// /// Defines an implicit conversion of a given to a . /// /// A to implicitly convert. [System.CLSCompliantAttribute(false)] - public static implicit operator JsonNode?(ulong? value) => value.HasValue ? new JsonValue(value.Value) : null; + public static implicit operator JsonNode?(ulong? value) => JsonValue.Create(value); /// /// Defines an explicit conversion of a given to a . 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 b040081281f95..6de74aef8ec3b 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 @@ -172,7 +172,7 @@ public JsonNode Root /// The current is not a or /// is not compatible with {TValue}. /// - public virtual TValue GetValue<[DynamicallyAccessedMembers(JsonHelpers.MembersAccessedOnRead)] TValue>() => + public virtual TValue GetValue() => throw new InvalidOperationException(SR.Format(SR.NodeWrongType, nameof(JsonValue))); /// diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValue.CreateOverloads.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValue.CreateOverloads.cs new file mode 100644 index 0000000000000..01faef0d2a1df --- /dev/null +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValue.CreateOverloads.cs @@ -0,0 +1,324 @@ +// 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; + +namespace System.Text.Json.Nodes +{ + public partial class JsonValue + { + /// + /// Initializes a new instance of the class that contains the specified value. + /// + /// The value to add. + /// Options to control the behavior. + /// The new instance of the class that contains the specified value. + public static JsonValue Create(bool value, JsonNodeOptions? options = null) => new JsonValue(value, JsonMetadataServices.BooleanConverter); + + /// + /// Initializes a new instance of the class that contains the specified value. + /// + /// The value to add. + /// Options to control the behavior. + /// The new instance of the class that contains the specified value. + public static JsonValue? Create(bool? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValue(value.Value, JsonMetadataServices.BooleanConverter) : null; + + /// + /// Initializes a new instance of the class that contains the specified value. + /// + /// The value to add. + /// Options to control the behavior. + /// The new instance of the class that contains the specified value. + public static JsonValue Create(byte value, JsonNodeOptions? options = null) => new JsonValue(value, JsonMetadataServices.ByteConverter); + + /// + /// Initializes a new instance of the class that contains the specified value. + /// + /// The value to add. + /// Options to control the behavior. + /// The new instance of the class that contains the specified value. + public static JsonValue? Create(byte? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValue(value.Value, JsonMetadataServices.ByteConverter) : null; + + /// + /// Initializes a new instance of the class that contains the specified value. + /// + /// The value to add. + /// Options to control the behavior. + /// The new instance of the class that contains the specified value. + public static JsonValue Create(char value, JsonNodeOptions? options = null) => new JsonValue(value, JsonMetadataServices.CharConverter); + + /// + /// Initializes a new instance of the class that contains the specified value. + /// + /// The value to add. + /// Options to control the behavior. + /// The new instance of the class that contains the specified value. + public static JsonValue? Create(char? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValue(value.Value, JsonMetadataServices.CharConverter) : null; + + /// + /// Initializes a new instance of the class that contains the specified value. + /// + /// The value to add. + /// Options to control the behavior. + /// The new instance of the class that contains the specified value. + public static JsonValue Create(DateTime value, JsonNodeOptions? options = null) => new JsonValue(value, JsonMetadataServices.DateTimeConverter); + + /// + /// Initializes a new instance of the class that contains the specified value. + /// + /// The value to add. + /// Options to control the behavior. + /// The new instance of the class that contains the specified value. + public static JsonValue? Create(DateTime? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValue(value.Value, JsonMetadataServices.DateTimeConverter) : null; + + /// + /// Initializes a new instance of the class that contains the specified value. + /// + /// The value to add. + /// Options to control the behavior. + /// The new instance of the class that contains the specified value. + public static JsonValue Create(DateTimeOffset value, JsonNodeOptions? options = null) => new JsonValue(value, JsonMetadataServices.DateTimeOffsetConverter); + + /// + /// Initializes a new instance of the class that contains the specified value. + /// + /// The value to add. + /// Options to control the behavior. + /// The new instance of the class that contains the specified value. + public static JsonValue? Create(DateTimeOffset? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValue(value.Value, JsonMetadataServices.DateTimeOffsetConverter) : null; + + /// + /// Initializes a new instance of the class that contains the specified value. + /// + /// The value to add. + /// Options to control the behavior. + /// The new instance of the class that contains the specified value. + public static JsonValue Create(decimal value, JsonNodeOptions? options = null) => new JsonValue(value, JsonMetadataServices.DecimalConverter); + + /// + /// Initializes a new instance of the class that contains the specified value. + /// + /// The value to add. + /// Options to control the behavior. + /// The new instance of the class that contains the specified value. + public static JsonValue? Create(decimal? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValue(value.Value, JsonMetadataServices.DecimalConverter) : null; + + /// + /// Initializes a new instance of the class that contains the specified value. + /// + /// The value to add. + /// Options to control the behavior. + /// The new instance of the class that contains the specified value. + public static JsonValue Create(double value, JsonNodeOptions? options = null) => new JsonValue(value, JsonMetadataServices.DoubleConverter); + + /// + /// Initializes a new instance of the class that contains the specified value. + /// + /// The value to add. + /// Options to control the behavior. + /// The new instance of the class that contains the specified value. + public static JsonValue? Create(double? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValue(value.Value, JsonMetadataServices.DoubleConverter) : null; + + /// + /// Initializes a new instance of the class that contains the specified value. + /// + /// The value to add. + /// Options to control the behavior. + /// The new instance of the class that contains the specified value. + public static JsonValue Create(Guid value, JsonNodeOptions? options = null) => new JsonValue(value, JsonMetadataServices.GuidConverter); + + /// + /// Initializes a new instance of the class that contains the specified value. + /// + /// The value to add. + /// Options to control the behavior. + /// The new instance of the class that contains the specified value. + public static JsonValue? Create(Guid? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValue(value.Value, JsonMetadataServices.GuidConverter) : null; + + /// + /// Initializes a new instance of the class that contains the specified value. + /// + /// The value to add. + /// Options to control the behavior. + /// The new instance of the class that contains the specified value. + public static JsonValue Create(short value, JsonNodeOptions? options = null) => new JsonValue(value, JsonMetadataServices.Int16Converter); + + /// + /// Initializes a new instance of the class that contains the specified value. + /// + /// The value to add. + /// Options to control the behavior. + /// The new instance of the class that contains the specified value. + public static JsonValue? Create(short? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValue(value.Value, JsonMetadataServices.Int16Converter) : null; + + /// + /// Initializes a new instance of the class that contains the specified value. + /// + /// The value to add. + /// Options to control the behavior. + /// The new instance of the class that contains the specified value. + public static JsonValue Create(int value, JsonNodeOptions? options = null) => new JsonValue(value, JsonMetadataServices.Int32Converter); + + /// + /// Initializes a new instance of the class that contains the specified value. + /// + /// The value to add. + /// Options to control the behavior. + /// The new instance of the class that contains the specified value. + public static JsonValue? Create(int? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValue(value.Value, JsonMetadataServices.Int32Converter) : null; + + /// + /// Initializes a new instance of the class that contains the specified value. + /// + /// The value to add. + /// Options to control the behavior. + /// The new instance of the class that contains the specified value. + public static JsonValue Create(long value, JsonNodeOptions? options = null) => new JsonValue(value, JsonMetadataServices.Int64Converter); + + /// + /// Initializes a new instance of the class that contains the specified value. + /// + /// The value to add. + /// Options to control the behavior. + /// The new instance of the class that contains the specified value. + public static JsonValue? Create(long? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValue(value.Value, JsonMetadataServices.Int64Converter) : null; + + /// + /// Initializes a new instance of the class that contains the specified value. + /// + /// The value to add. + /// Options to control the behavior. + /// The new instance of the class that contains the specified value. + [CLSCompliantAttribute(false)] + public static JsonValue Create(sbyte value, JsonNodeOptions? options = null) => new JsonValue(value, JsonMetadataServices.SByteConverter); + + /// + /// Initializes a new instance of the class that contains the specified value. + /// + /// The value to add. + /// Options to control the behavior. + /// The new instance of the class that contains the specified value. + [CLSCompliantAttribute(false)] + public static JsonValue? Create(sbyte? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValue(value.Value, JsonMetadataServices.SByteConverter) : null; + + /// + /// Initializes a new instance of the class that contains the specified value. + /// + /// The value to add. + /// Options to control the behavior. + /// The new instance of the class that contains the specified value. + public static JsonValue Create(float value, JsonNodeOptions? options = null) => new JsonValue(value, JsonMetadataServices.SingleConverter); + + /// + /// Initializes a new instance of the class that contains the specified value. + /// + /// The value to add. + /// Options to control the behavior. + /// The new instance of the class that contains the specified value. + public static JsonValue? Create(float? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValue(value.Value, JsonMetadataServices.SingleConverter) : null; + + /// + /// Initializes a new instance of the class that contains the specified value. + /// + /// The value to add. + /// Options to control the behavior. + /// The new instance of the class that contains the specified value. + public static JsonValue? Create(string? value, JsonNodeOptions? options = null) => value != null ? new JsonValue(value, JsonMetadataServices.StringConverter) : null; + + /// + /// Initializes a new instance of the class that contains the specified value. + /// + /// The value to add. + /// Options to control the behavior. + /// The new instance of the class that contains the specified value. + [CLSCompliantAttribute(false)] + public static JsonValue Create(ushort value, JsonNodeOptions? options = null) => new JsonValue(value, JsonMetadataServices.UInt16Converter); + + /// + /// Initializes a new instance of the class that contains the specified value. + /// + /// The value to add. + /// Options to control the behavior. + /// The new instance of the class that contains the specified value. + [CLSCompliantAttribute(false)] + public static JsonValue? Create(ushort? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValue(value.Value, JsonMetadataServices.UInt16Converter) : null; + + /// + /// Initializes a new instance of the class that contains the specified value. + /// + /// The value to add. + /// Options to control the behavior. + /// The new instance of the class that contains the specified value. + [CLSCompliantAttribute(false)] + public static JsonValue Create(uint value, JsonNodeOptions? options = null) => new JsonValue(value, JsonMetadataServices.UInt32Converter); + + /// + /// Initializes a new instance of the class that contains the specified value. + /// + /// The value to add. + /// Options to control the behavior. + /// The new instance of the class that contains the specified value. + [CLSCompliantAttribute(false)] + public static JsonValue? Create(uint? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValue(value.Value, JsonMetadataServices.UInt32Converter) : null; + + /// + /// Initializes a new instance of the class that contains the specified value. + /// + /// The value to add. + /// Options to control the behavior. + /// The new instance of the class that contains the specified value. + [CLSCompliantAttribute(false)] + public static JsonValue Create(ulong value, JsonNodeOptions? options = null) => new JsonValue(value, JsonMetadataServices.UInt64Converter); + + /// + /// Initializes a new instance of the class that contains the specified value. + /// + /// The value to add. + /// Options to control the behavior. + /// The new instance of the class that contains the specified value. + [CLSCompliantAttribute(false)] + public static JsonValue? Create(ulong? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValue(value.Value, JsonMetadataServices.UInt64Converter) : null; + + /// + /// Initializes a new instance of the class that contains the specified value. + /// + /// The value to add. + /// Options to control the behavior. + /// The new instance of the class that contains the specified value. + public static JsonValue? Create(JsonElement value, JsonNodeOptions? options = null) + { + if (value.ValueKind == JsonValueKind.Null) + { + return null; + } + + VerifyJsonElementIsNotArrayOrObject(ref value); + + return new JsonValue(value, JsonMetadataServices.JsonElementConverter); + } + + /// + /// Initializes a new instance of the class that contains the specified value. + /// + /// The value to add. + /// Options to control the behavior. + /// The new instance of the class that contains the specified value. + public static JsonValue? Create(JsonElement? value, JsonNodeOptions? options = null) + { + if (value == null) + { + return null; + } + + JsonElement element = value.Value; + if (element.ValueKind == JsonValueKind.Null) + { + return null; + } + + VerifyJsonElementIsNotArrayOrObject(ref element); + + return new JsonValue(element, JsonMetadataServices.JsonElementConverter); + } + } +} diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValue.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValue.cs index 7aed25fa4fe69..f459b82864aa4 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValue.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValue.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Text.Json.Serialization.Metadata; namespace System.Text.Json.Nodes { @@ -20,11 +21,11 @@ private protected JsonValue(JsonNodeOptions? options = null) : base(options) { } /// /// The new instance of the class that contains the specified value. /// - /// The type of value to be added. - /// The value to add. + /// The type of value to create. + /// The value to create. /// Options to control the behavior. /// The new instance of the class that contains the specified value. - public static JsonValue? Create(T? value, JsonNodeOptions? options = null) + public static JsonValue? Create<[DynamicallyAccessedMembers(JsonHelpers.MembersAccessedOnRead)]T>(T? value, JsonNodeOptions? options = null) { if (value == null) { @@ -38,13 +39,46 @@ private protected JsonValue(JsonNodeOptions? options = null) : base(options) { } return null; } - if (element.ValueKind == JsonValueKind.Object || element.ValueKind == JsonValueKind.Array) + VerifyJsonElementIsNotArrayOrObject(ref element); + } + + return new JsonValue(value, options); + } + + /// + /// Initializes a new instance of the class that contains the specified value. + /// + /// + /// The new instance of the class that contains the specified value. + /// + /// The type of value to create. + /// The value to create. + /// The that is later used to serialize the value. + /// Options to control the behavior. + /// The new instance of the class that contains the specified value. + public static JsonValue? Create(T? value, JsonTypeInfo jsonTypeInfo, JsonNodeOptions? options = null) + { + if (jsonTypeInfo == null) + { + throw new ArgumentNullException(nameof(jsonTypeInfo)); + } + + if (value == null) + { + return null; + } + + if (value is JsonElement element) + { + if (element.ValueKind == JsonValueKind.Null) { - throw new InvalidOperationException(SR.NodeElementCannotBeObjectOrArray); + return null; } + + VerifyJsonElementIsNotArrayOrObject(ref element); } - return new JsonValue(value, options); + return new JsonValue(value, jsonTypeInfo, options); } internal override void GetPath(List path, JsonNode? child) @@ -64,5 +98,14 @@ internal override void GetPath(List path, JsonNode? child) /// When this method returns, contains the parsed value. /// if the value can be successfully obtained; otherwise, . public abstract bool TryGetValue([NotNullWhen(true)] out T? value); + + private static void VerifyJsonElementIsNotArrayOrObject(ref JsonElement element) + { + // Force usage of JsonArray and JsonObject instead of supporting those in an JsonValue. + if (element.ValueKind == JsonValueKind.Object || element.ValueKind == JsonValueKind.Array) + { + throw new InvalidOperationException(SR.NodeElementCannotBeObjectOrArray); + } + } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValueOfT.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValueOfT.cs index 0aa190565d22d..2931a1241e771 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValueOfT.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValueOfT.cs @@ -3,6 +3,8 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; namespace System.Text.Json.Nodes { @@ -10,7 +12,9 @@ namespace System.Text.Json.Nodes [DebuggerTypeProxy(typeof(JsonValue<>.DebugView))] internal sealed partial class JsonValue : JsonValue { - internal readonly TValue _value; // keep as a field for direct access to avoid copies + public readonly TValue _value; // keep as a field for direct access to avoid copies + public readonly JsonTypeInfo? _jsonTypeInfo; + public readonly JsonConverter? _converter; public JsonValue(TValue value, JsonNodeOptions? options = null) : base(options) { @@ -25,6 +29,34 @@ public JsonValue(TValue value, JsonNodeOptions? options = null) : base(options) _value = value; } + public JsonValue(TValue value, JsonTypeInfo jsonTypeInfo, JsonNodeOptions? options = null) : base(options) + { + Debug.Assert(value != null); + Debug.Assert(!(value is JsonElement) || ((JsonElement)(object)value).ValueKind != JsonValueKind.Null); + + if (value is JsonNode) + { + ThrowHelper.ThrowArgumentException_NodeValueNotAllowed(nameof(value)); + } + + _value = value; + _jsonTypeInfo = jsonTypeInfo; + } + + public JsonValue(TValue value, JsonConverter converter, JsonNodeOptions? options = null) : base(options) + { + Debug.Assert(value != null); + Debug.Assert(!(value is JsonElement) || ((JsonElement)(object)value).ValueKind != JsonValueKind.Null); + + if (value is JsonNode) + { + ThrowHelper.ThrowArgumentException_NodeValueNotAllowed(nameof(value)); + } + + _value = value; + _converter = converter; + } + public TValue Value { get @@ -33,7 +65,7 @@ public TValue Value } } - public override T GetValue<[DynamicallyAccessedMembers(JsonHelpers.MembersAccessedOnRead)] T>() + public override T GetValue() { // If no conversion is needed, just return the raw value. if (_value is T returnValue) @@ -86,7 +118,27 @@ public override void WriteTo(Utf8JsonWriter writer, JsonSerializerOptions? optio } else { - JsonSerializer.Serialize(writer, _value, _value!.GetType(), options); + if (_converter != null) + { + options ??= JsonSerializerOptions.s_defaultOptions; + + if (_converter.IsInternalConverterForNumberType) + { + _converter.WriteNumberWithCustomHandling(writer, _value, options.NumberHandling); + } + else + { + _converter.Write(writer, _value, options); + } + } + else if (_jsonTypeInfo != null) + { + JsonSerializer.Serialize(writer, _value, _jsonTypeInfo); + } + else + { + JsonSerializer.Serialize(writer, _value, options); + } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Node/JsonNodeConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Node/JsonNodeConverter.cs index 867a9bcf2caf5..058ec499faf40 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Node/JsonNodeConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Node/JsonNodeConverter.cs @@ -30,18 +30,18 @@ public override void Write(Utf8JsonWriter writer, object? value, JsonSerializerO } else { - if (value is JsonObject jsonObject) + if (value is JsonValue jsonValue) { - ObjectConverter.Write(writer, jsonObject, options); + ValueConverter.Write(writer, jsonValue, options); } - else if (value is JsonArray jsonArray) + else if (value is JsonObject jsonObject) { - ArrayConverter.Write(writer, (JsonArray)value, options); + ObjectConverter.Write(writer, jsonObject, options); } else { - Debug.Assert(value is JsonValue); - ValueConverter.Write(writer, (JsonValue)value, options); + Debug.Assert(value is JsonArray); + ArrayConverter.Write(writer, (JsonArray)value, options); } } } @@ -55,10 +55,10 @@ public override void Write(Utf8JsonWriter writer, object? value, JsonSerializerO case JsonTokenType.True: case JsonTokenType.Number: return ValueConverter.Read(ref reader, typeToConvert, options); - case JsonTokenType.StartArray: - return ArrayConverter.Read(ref reader, typeToConvert, options); case JsonTokenType.StartObject: return ObjectConverter.Read(ref reader, typeToConvert, options); + case JsonTokenType.StartArray: + return ArrayConverter.Read(ref reader, typeToConvert, options); default: Debug.Assert(false); throw new JsonException(); diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonNode/JsonValueTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonNode/JsonValueTests.cs index b83d7f29a8322..61cd70b3a95ca 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonNode/JsonValueTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonNode/JsonValueTests.cs @@ -12,7 +12,16 @@ public static class JsonValueTests [Fact] public static void CreateFromNull() { + Assert.Null(JsonValue.Create((bool?)null)); + Assert.Null(JsonValue.Create((string)null)); + Assert.Null(JsonValue.Create((JsonElement?)null)); + Assert.Null(JsonValue.Create(JsonDocument.Parse("null").RootElement)); + Assert.Null(JsonValue.Create((object)null)); + Assert.Null(JsonValue.Create((bool?)null)); + Assert.Null(JsonValue.Create((string)null)); + Assert.Null(JsonValue.Create((JsonElement?)null)); + Assert.Null(JsonValue.Create(JsonDocument.Parse("null").RootElement)); } [Fact] From 24f095468a45ddec9a9010036eba7e314f1d553d Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Wed, 19 May 2021 13:55:15 -0500 Subject: [PATCH 2/3] Fix issue with object converter pulling in all converters --- .../System.Text.Json/ref/System.Text.Json.cs | 2 + .../src/ILLink/ILLink.Suppressions.xml | 6 +- .../src/System.Text.Json.csproj | 2 + .../src/System/Text/Json/Nodes/JsonArray.cs | 5 +- .../Text/Json/Nodes/JsonObject.Dynamic.cs | 2 +- .../Json/Nodes/JsonValue.CreateOverloads.cs | 70 +++++++++--------- .../src/System/Text/Json/Nodes/JsonValue.cs | 5 +- .../Text/Json/Nodes/JsonValueNotTrimmable.cs | 25 +++++++ .../System/Text/Json/Nodes/JsonValueOfT.cs | 71 +------------------ .../Text/Json/Nodes/JsonValueTrimmable.cs | 55 ++++++++++++++ .../Converters/Node/JsonNodeConverter.cs | 3 +- .../Converters/Node/JsonValueConverter.cs | 3 +- 12 files changed, 134 insertions(+), 115 deletions(-) create mode 100644 src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValueNotTrimmable.cs create mode 100644 src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValueTrimmable.cs 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 44e108135c00c..29c08c9ba1f7a 100644 --- a/src/libraries/System.Text.Json/ref/System.Text.Json.cs +++ b/src/libraries/System.Text.Json/ref/System.Text.Json.cs @@ -518,6 +518,7 @@ public JsonArray(params System.Text.Json.Nodes.JsonNode?[] items) { } public int Count { get { throw null; } } bool System.Collections.Generic.ICollection.IsReadOnly { get { throw null; } } public void Add(System.Text.Json.Nodes.JsonNode? item) { } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")] public void Add<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] T>(T? value) { } public void Clear() { } public bool Contains(System.Text.Json.Nodes.JsonNode? item) { throw null; } @@ -710,6 +711,7 @@ public abstract partial class JsonValue : System.Text.Json.Nodes.JsonNode [System.CLSCompliantAttribute(false)] public static System.Text.Json.Nodes.JsonValue Create(ulong value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } public static System.Text.Json.Nodes.JsonValue? Create(T? value, System.Text.Json.Serialization.Metadata.JsonTypeInfo jsonTypeInfo, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")] public static System.Text.Json.Nodes.JsonValue? Create<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] T>(T? value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } public abstract bool TryGetValue([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out T? value); } diff --git a/src/libraries/System.Text.Json/src/ILLink/ILLink.Suppressions.xml b/src/libraries/System.Text.Json/src/ILLink/ILLink.Suppressions.xml index 3a89fcb3f29d5..420744b19752f 100644 --- a/src/libraries/System.Text.Json/src/ILLink/ILLink.Suppressions.xml +++ b/src/libraries/System.Text.Json/src/ILLink/ILLink.Suppressions.xml @@ -5,13 +5,13 @@ ILLink IL2026 member - M:System.Text.Json.Nodes.JsonValue`1.WriteTo(System.Text.Json.Utf8JsonWriter,System.Text.Json.JsonSerializerOptions) + M:System.Text.Json.Nodes.JsonValueNotTrimmable`1.WriteTo(System.Text.Json.Utf8JsonWriter,System.Text.Json.JsonSerializerOptions) ILLink - IL2072 + IL2091 member - M:System.Text.Json.Nodes.JsonValue`1.WriteTo(System.Text.Json.Utf8JsonWriter,System.Text.Json.JsonSerializerOptions) + M:System.Text.Json.Nodes.JsonValueNotTrimmable`1.WriteTo(System.Text.Json.Utf8JsonWriter,System.Text.Json.JsonSerializerOptions) 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 4f0e103254645..90c3695734ca7 100644 --- a/src/libraries/System.Text.Json/src/System.Text.Json.csproj +++ b/src/libraries/System.Text.Json/src/System.Text.Json.csproj @@ -62,7 +62,9 @@ + + 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 4ed453aaf67a5..d8e224bc20de4 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 @@ -98,7 +98,8 @@ internal JsonArray (JsonElement element, JsonNodeOptions? options = null) : base /// /// The object to be added to the end of the . /// - public void Add<[DynamicallyAccessedMembers(JsonHelpers.MembersAccessedOnRead)] T>(T? value) + [RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)] + public void Add<[DynamicallyAccessedMembers(JsonHelpers.MembersAccessedOnRead)]T>(T? value) { if (value == null) { @@ -109,7 +110,7 @@ internal JsonArray (JsonElement element, JsonNodeOptions? options = null) : base JsonNode? jNode = value as JsonNode; if (jNode == null) { - jNode = new JsonValue(value); + jNode = new JsonValueNotTrimmable(value); } // Call the IList.Add() implementation. diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonObject.Dynamic.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonObject.Dynamic.cs index c9098800a819c..3bd87615e550a 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonObject.Dynamic.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonObject.Dynamic.cs @@ -29,7 +29,7 @@ private bool TrySetMemberCallback(SetMemberBinder binder, object? value) node = value as JsonNode; if (node == null) { - node = new JsonValue(value, Options); + node = new JsonValueNotTrimmable(value, Options); } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValue.CreateOverloads.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValue.CreateOverloads.cs index 01faef0d2a1df..db055815f97a0 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValue.CreateOverloads.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValue.CreateOverloads.cs @@ -13,7 +13,7 @@ public partial class JsonValue /// The value to add. /// Options to control the behavior. /// The new instance of the class that contains the specified value. - public static JsonValue Create(bool value, JsonNodeOptions? options = null) => new JsonValue(value, JsonMetadataServices.BooleanConverter); + public static JsonValue Create(bool value, JsonNodeOptions? options = null) => new JsonValueTrimmable(value, JsonMetadataServices.BooleanConverter); /// /// Initializes a new instance of the class that contains the specified value. @@ -21,7 +21,7 @@ public partial class JsonValue /// The value to add. /// Options to control the behavior. /// The new instance of the class that contains the specified value. - public static JsonValue? Create(bool? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValue(value.Value, JsonMetadataServices.BooleanConverter) : null; + public static JsonValue? Create(bool? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValueTrimmable(value.Value, JsonMetadataServices.BooleanConverter) : null; /// /// Initializes a new instance of the class that contains the specified value. @@ -29,7 +29,7 @@ public partial class JsonValue /// The value to add. /// Options to control the behavior. /// The new instance of the class that contains the specified value. - public static JsonValue Create(byte value, JsonNodeOptions? options = null) => new JsonValue(value, JsonMetadataServices.ByteConverter); + public static JsonValue Create(byte value, JsonNodeOptions? options = null) => new JsonValueTrimmable(value, JsonMetadataServices.ByteConverter); /// /// Initializes a new instance of the class that contains the specified value. @@ -37,7 +37,7 @@ public partial class JsonValue /// The value to add. /// Options to control the behavior. /// The new instance of the class that contains the specified value. - public static JsonValue? Create(byte? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValue(value.Value, JsonMetadataServices.ByteConverter) : null; + public static JsonValue? Create(byte? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValueTrimmable(value.Value, JsonMetadataServices.ByteConverter) : null; /// /// Initializes a new instance of the class that contains the specified value. @@ -45,7 +45,7 @@ public partial class JsonValue /// The value to add. /// Options to control the behavior. /// The new instance of the class that contains the specified value. - public static JsonValue Create(char value, JsonNodeOptions? options = null) => new JsonValue(value, JsonMetadataServices.CharConverter); + public static JsonValue Create(char value, JsonNodeOptions? options = null) => new JsonValueTrimmable(value, JsonMetadataServices.CharConverter); /// /// Initializes a new instance of the class that contains the specified value. @@ -53,7 +53,7 @@ public partial class JsonValue /// The value to add. /// Options to control the behavior. /// The new instance of the class that contains the specified value. - public static JsonValue? Create(char? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValue(value.Value, JsonMetadataServices.CharConverter) : null; + public static JsonValue? Create(char? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValueTrimmable(value.Value, JsonMetadataServices.CharConverter) : null; /// /// Initializes a new instance of the class that contains the specified value. @@ -61,7 +61,7 @@ public partial class JsonValue /// The value to add. /// Options to control the behavior. /// The new instance of the class that contains the specified value. - public static JsonValue Create(DateTime value, JsonNodeOptions? options = null) => new JsonValue(value, JsonMetadataServices.DateTimeConverter); + public static JsonValue Create(DateTime value, JsonNodeOptions? options = null) => new JsonValueTrimmable(value, JsonMetadataServices.DateTimeConverter); /// /// Initializes a new instance of the class that contains the specified value. @@ -69,7 +69,7 @@ public partial class JsonValue /// The value to add. /// Options to control the behavior. /// The new instance of the class that contains the specified value. - public static JsonValue? Create(DateTime? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValue(value.Value, JsonMetadataServices.DateTimeConverter) : null; + public static JsonValue? Create(DateTime? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValueTrimmable(value.Value, JsonMetadataServices.DateTimeConverter) : null; /// /// Initializes a new instance of the class that contains the specified value. @@ -77,7 +77,7 @@ public partial class JsonValue /// The value to add. /// Options to control the behavior. /// The new instance of the class that contains the specified value. - public static JsonValue Create(DateTimeOffset value, JsonNodeOptions? options = null) => new JsonValue(value, JsonMetadataServices.DateTimeOffsetConverter); + public static JsonValue Create(DateTimeOffset value, JsonNodeOptions? options = null) => new JsonValueTrimmable(value, JsonMetadataServices.DateTimeOffsetConverter); /// /// Initializes a new instance of the class that contains the specified value. @@ -85,7 +85,7 @@ public partial class JsonValue /// The value to add. /// Options to control the behavior. /// The new instance of the class that contains the specified value. - public static JsonValue? Create(DateTimeOffset? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValue(value.Value, JsonMetadataServices.DateTimeOffsetConverter) : null; + public static JsonValue? Create(DateTimeOffset? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValueTrimmable(value.Value, JsonMetadataServices.DateTimeOffsetConverter) : null; /// /// Initializes a new instance of the class that contains the specified value. @@ -93,7 +93,7 @@ public partial class JsonValue /// The value to add. /// Options to control the behavior. /// The new instance of the class that contains the specified value. - public static JsonValue Create(decimal value, JsonNodeOptions? options = null) => new JsonValue(value, JsonMetadataServices.DecimalConverter); + public static JsonValue Create(decimal value, JsonNodeOptions? options = null) => new JsonValueTrimmable(value, JsonMetadataServices.DecimalConverter); /// /// Initializes a new instance of the class that contains the specified value. @@ -101,7 +101,7 @@ public partial class JsonValue /// The value to add. /// Options to control the behavior. /// The new instance of the class that contains the specified value. - public static JsonValue? Create(decimal? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValue(value.Value, JsonMetadataServices.DecimalConverter) : null; + public static JsonValue? Create(decimal? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValueTrimmable(value.Value, JsonMetadataServices.DecimalConverter) : null; /// /// Initializes a new instance of the class that contains the specified value. @@ -109,7 +109,7 @@ public partial class JsonValue /// The value to add. /// Options to control the behavior. /// The new instance of the class that contains the specified value. - public static JsonValue Create(double value, JsonNodeOptions? options = null) => new JsonValue(value, JsonMetadataServices.DoubleConverter); + public static JsonValue Create(double value, JsonNodeOptions? options = null) => new JsonValueTrimmable(value, JsonMetadataServices.DoubleConverter); /// /// Initializes a new instance of the class that contains the specified value. @@ -117,7 +117,7 @@ public partial class JsonValue /// The value to add. /// Options to control the behavior. /// The new instance of the class that contains the specified value. - public static JsonValue? Create(double? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValue(value.Value, JsonMetadataServices.DoubleConverter) : null; + public static JsonValue? Create(double? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValueTrimmable(value.Value, JsonMetadataServices.DoubleConverter) : null; /// /// Initializes a new instance of the class that contains the specified value. @@ -125,7 +125,7 @@ public partial class JsonValue /// The value to add. /// Options to control the behavior. /// The new instance of the class that contains the specified value. - public static JsonValue Create(Guid value, JsonNodeOptions? options = null) => new JsonValue(value, JsonMetadataServices.GuidConverter); + public static JsonValue Create(Guid value, JsonNodeOptions? options = null) => new JsonValueTrimmable(value, JsonMetadataServices.GuidConverter); /// /// Initializes a new instance of the class that contains the specified value. @@ -133,7 +133,7 @@ public partial class JsonValue /// The value to add. /// Options to control the behavior. /// The new instance of the class that contains the specified value. - public static JsonValue? Create(Guid? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValue(value.Value, JsonMetadataServices.GuidConverter) : null; + public static JsonValue? Create(Guid? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValueTrimmable(value.Value, JsonMetadataServices.GuidConverter) : null; /// /// Initializes a new instance of the class that contains the specified value. @@ -141,7 +141,7 @@ public partial class JsonValue /// The value to add. /// Options to control the behavior. /// The new instance of the class that contains the specified value. - public static JsonValue Create(short value, JsonNodeOptions? options = null) => new JsonValue(value, JsonMetadataServices.Int16Converter); + public static JsonValue Create(short value, JsonNodeOptions? options = null) => new JsonValueTrimmable(value, JsonMetadataServices.Int16Converter); /// /// Initializes a new instance of the class that contains the specified value. @@ -149,7 +149,7 @@ public partial class JsonValue /// The value to add. /// Options to control the behavior. /// The new instance of the class that contains the specified value. - public static JsonValue? Create(short? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValue(value.Value, JsonMetadataServices.Int16Converter) : null; + public static JsonValue? Create(short? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValueTrimmable(value.Value, JsonMetadataServices.Int16Converter) : null; /// /// Initializes a new instance of the class that contains the specified value. @@ -157,7 +157,7 @@ public partial class JsonValue /// The value to add. /// Options to control the behavior. /// The new instance of the class that contains the specified value. - public static JsonValue Create(int value, JsonNodeOptions? options = null) => new JsonValue(value, JsonMetadataServices.Int32Converter); + public static JsonValue Create(int value, JsonNodeOptions? options = null) => new JsonValueTrimmable(value, JsonMetadataServices.Int32Converter); /// /// Initializes a new instance of the class that contains the specified value. @@ -165,7 +165,7 @@ public partial class JsonValue /// The value to add. /// Options to control the behavior. /// The new instance of the class that contains the specified value. - public static JsonValue? Create(int? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValue(value.Value, JsonMetadataServices.Int32Converter) : null; + public static JsonValue? Create(int? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValueTrimmable(value.Value, JsonMetadataServices.Int32Converter) : null; /// /// Initializes a new instance of the class that contains the specified value. @@ -173,7 +173,7 @@ public partial class JsonValue /// The value to add. /// Options to control the behavior. /// The new instance of the class that contains the specified value. - public static JsonValue Create(long value, JsonNodeOptions? options = null) => new JsonValue(value, JsonMetadataServices.Int64Converter); + public static JsonValue Create(long value, JsonNodeOptions? options = null) => new JsonValueTrimmable(value, JsonMetadataServices.Int64Converter); /// /// Initializes a new instance of the class that contains the specified value. @@ -181,7 +181,7 @@ public partial class JsonValue /// The value to add. /// Options to control the behavior. /// The new instance of the class that contains the specified value. - public static JsonValue? Create(long? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValue(value.Value, JsonMetadataServices.Int64Converter) : null; + public static JsonValue? Create(long? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValueTrimmable(value.Value, JsonMetadataServices.Int64Converter) : null; /// /// Initializes a new instance of the class that contains the specified value. @@ -190,7 +190,7 @@ public partial class JsonValue /// Options to control the behavior. /// The new instance of the class that contains the specified value. [CLSCompliantAttribute(false)] - public static JsonValue Create(sbyte value, JsonNodeOptions? options = null) => new JsonValue(value, JsonMetadataServices.SByteConverter); + public static JsonValue Create(sbyte value, JsonNodeOptions? options = null) => new JsonValueTrimmable(value, JsonMetadataServices.SByteConverter); /// /// Initializes a new instance of the class that contains the specified value. @@ -199,7 +199,7 @@ public partial class JsonValue /// Options to control the behavior. /// The new instance of the class that contains the specified value. [CLSCompliantAttribute(false)] - public static JsonValue? Create(sbyte? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValue(value.Value, JsonMetadataServices.SByteConverter) : null; + public static JsonValue? Create(sbyte? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValueTrimmable(value.Value, JsonMetadataServices.SByteConverter) : null; /// /// Initializes a new instance of the class that contains the specified value. @@ -207,7 +207,7 @@ public partial class JsonValue /// The value to add. /// Options to control the behavior. /// The new instance of the class that contains the specified value. - public static JsonValue Create(float value, JsonNodeOptions? options = null) => new JsonValue(value, JsonMetadataServices.SingleConverter); + public static JsonValue Create(float value, JsonNodeOptions? options = null) => new JsonValueTrimmable(value, JsonMetadataServices.SingleConverter); /// /// Initializes a new instance of the class that contains the specified value. @@ -215,7 +215,7 @@ public partial class JsonValue /// The value to add. /// Options to control the behavior. /// The new instance of the class that contains the specified value. - public static JsonValue? Create(float? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValue(value.Value, JsonMetadataServices.SingleConverter) : null; + public static JsonValue? Create(float? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValueTrimmable(value.Value, JsonMetadataServices.SingleConverter) : null; /// /// Initializes a new instance of the class that contains the specified value. @@ -223,7 +223,7 @@ public partial class JsonValue /// The value to add. /// Options to control the behavior. /// The new instance of the class that contains the specified value. - public static JsonValue? Create(string? value, JsonNodeOptions? options = null) => value != null ? new JsonValue(value, JsonMetadataServices.StringConverter) : null; + public static JsonValue? Create(string? value, JsonNodeOptions? options = null) => value != null ? new JsonValueTrimmable(value, JsonMetadataServices.StringConverter) : null; /// /// Initializes a new instance of the class that contains the specified value. @@ -232,7 +232,7 @@ public partial class JsonValue /// Options to control the behavior. /// The new instance of the class that contains the specified value. [CLSCompliantAttribute(false)] - public static JsonValue Create(ushort value, JsonNodeOptions? options = null) => new JsonValue(value, JsonMetadataServices.UInt16Converter); + public static JsonValue Create(ushort value, JsonNodeOptions? options = null) => new JsonValueTrimmable(value, JsonMetadataServices.UInt16Converter); /// /// Initializes a new instance of the class that contains the specified value. @@ -241,7 +241,7 @@ public partial class JsonValue /// Options to control the behavior. /// The new instance of the class that contains the specified value. [CLSCompliantAttribute(false)] - public static JsonValue? Create(ushort? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValue(value.Value, JsonMetadataServices.UInt16Converter) : null; + public static JsonValue? Create(ushort? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValueTrimmable(value.Value, JsonMetadataServices.UInt16Converter) : null; /// /// Initializes a new instance of the class that contains the specified value. @@ -250,7 +250,7 @@ public partial class JsonValue /// Options to control the behavior. /// The new instance of the class that contains the specified value. [CLSCompliantAttribute(false)] - public static JsonValue Create(uint value, JsonNodeOptions? options = null) => new JsonValue(value, JsonMetadataServices.UInt32Converter); + public static JsonValue Create(uint value, JsonNodeOptions? options = null) => new JsonValueTrimmable(value, JsonMetadataServices.UInt32Converter); /// /// Initializes a new instance of the class that contains the specified value. @@ -259,7 +259,7 @@ public partial class JsonValue /// Options to control the behavior. /// The new instance of the class that contains the specified value. [CLSCompliantAttribute(false)] - public static JsonValue? Create(uint? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValue(value.Value, JsonMetadataServices.UInt32Converter) : null; + public static JsonValue? Create(uint? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValueTrimmable(value.Value, JsonMetadataServices.UInt32Converter) : null; /// /// Initializes a new instance of the class that contains the specified value. @@ -268,7 +268,7 @@ public partial class JsonValue /// Options to control the behavior. /// The new instance of the class that contains the specified value. [CLSCompliantAttribute(false)] - public static JsonValue Create(ulong value, JsonNodeOptions? options = null) => new JsonValue(value, JsonMetadataServices.UInt64Converter); + public static JsonValue Create(ulong value, JsonNodeOptions? options = null) => new JsonValueTrimmable(value, JsonMetadataServices.UInt64Converter); /// /// Initializes a new instance of the class that contains the specified value. @@ -277,7 +277,7 @@ public partial class JsonValue /// Options to control the behavior. /// The new instance of the class that contains the specified value. [CLSCompliantAttribute(false)] - public static JsonValue? Create(ulong? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValue(value.Value, JsonMetadataServices.UInt64Converter) : null; + public static JsonValue? Create(ulong? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValueTrimmable(value.Value, JsonMetadataServices.UInt64Converter) : null; /// /// Initializes a new instance of the class that contains the specified value. @@ -294,7 +294,7 @@ public partial class JsonValue VerifyJsonElementIsNotArrayOrObject(ref value); - return new JsonValue(value, JsonMetadataServices.JsonElementConverter); + return new JsonValueTrimmable(value, JsonMetadataServices.JsonElementConverter); } /// @@ -318,7 +318,7 @@ public partial class JsonValue VerifyJsonElementIsNotArrayOrObject(ref element); - return new JsonValue(element, JsonMetadataServices.JsonElementConverter); + return new JsonValueTrimmable(element, JsonMetadataServices.JsonElementConverter); } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValue.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValue.cs index f459b82864aa4..c199ad13788af 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValue.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValue.cs @@ -25,6 +25,7 @@ private protected JsonValue(JsonNodeOptions? options = null) : base(options) { } /// The value to create. /// Options to control the behavior. /// The new instance of the class that contains the specified value. + [RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)] public static JsonValue? Create<[DynamicallyAccessedMembers(JsonHelpers.MembersAccessedOnRead)]T>(T? value, JsonNodeOptions? options = null) { if (value == null) @@ -42,7 +43,7 @@ private protected JsonValue(JsonNodeOptions? options = null) : base(options) { } VerifyJsonElementIsNotArrayOrObject(ref element); } - return new JsonValue(value, options); + return new JsonValueNotTrimmable(value, options); } /// @@ -78,7 +79,7 @@ private protected JsonValue(JsonNodeOptions? options = null) : base(options) { } VerifyJsonElementIsNotArrayOrObject(ref element); } - return new JsonValue(value, jsonTypeInfo, options); + return new JsonValueTrimmable(value, jsonTypeInfo, options); } internal override void GetPath(List path, JsonNode? child) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValueNotTrimmable.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValueNotTrimmable.cs new file mode 100644 index 0000000000000..a45cd48994190 --- /dev/null +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValueNotTrimmable.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Text.Json.Nodes +{ + /// + /// Not trim-safe since it calls JsonSerializer.Serialize(JsonSerializerOptions). + /// + internal sealed partial class JsonValueNotTrimmable : JsonValue + { + public JsonValueNotTrimmable(TValue value, JsonNodeOptions? options = null) : base(value, options) + { + } + + public override void WriteTo(Utf8JsonWriter writer, JsonSerializerOptions? options = null) + { + if (writer == null) + { + throw new ArgumentNullException(nameof(writer)); + } + + JsonSerializer.Serialize(writer, _value, options); + } + } +} diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValueOfT.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValueOfT.cs index 2931a1241e771..e7bc7b3f86d46 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValueOfT.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValueOfT.cs @@ -3,18 +3,14 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Text.Json.Serialization; -using System.Text.Json.Serialization.Metadata; namespace System.Text.Json.Nodes { [DebuggerDisplay("{ToJsonString(),nq}")] [DebuggerTypeProxy(typeof(JsonValue<>.DebugView))] - internal sealed partial class JsonValue : JsonValue + internal abstract partial class JsonValue : JsonValue { public readonly TValue _value; // keep as a field for direct access to avoid copies - public readonly JsonTypeInfo? _jsonTypeInfo; - public readonly JsonConverter? _converter; public JsonValue(TValue value, JsonNodeOptions? options = null) : base(options) { @@ -29,34 +25,6 @@ public JsonValue(TValue value, JsonNodeOptions? options = null) : base(options) _value = value; } - public JsonValue(TValue value, JsonTypeInfo jsonTypeInfo, JsonNodeOptions? options = null) : base(options) - { - Debug.Assert(value != null); - Debug.Assert(!(value is JsonElement) || ((JsonElement)(object)value).ValueKind != JsonValueKind.Null); - - if (value is JsonNode) - { - ThrowHelper.ThrowArgumentException_NodeValueNotAllowed(nameof(value)); - } - - _value = value; - _jsonTypeInfo = jsonTypeInfo; - } - - public JsonValue(TValue value, JsonConverter converter, JsonNodeOptions? options = null) : base(options) - { - Debug.Assert(value != null); - Debug.Assert(!(value is JsonElement) || ((JsonElement)(object)value).ValueKind != JsonValueKind.Null); - - if (value is JsonNode) - { - ThrowHelper.ThrowArgumentException_NodeValueNotAllowed(nameof(value)); - } - - _value = value; - _converter = converter; - } - public TValue Value { get @@ -105,43 +73,6 @@ public override bool TryGetValue([NotNullWhen(true)] out T value) return false; } - public override void WriteTo(Utf8JsonWriter writer, JsonSerializerOptions? options = null) - { - if (writer == null) - { - throw new ArgumentNullException(nameof(writer)); - } - - if (_value is JsonElement jsonElement) - { - jsonElement.WriteTo(writer); - } - else - { - if (_converter != null) - { - options ??= JsonSerializerOptions.s_defaultOptions; - - if (_converter.IsInternalConverterForNumberType) - { - _converter.WriteNumberWithCustomHandling(writer, _value, options.NumberHandling); - } - else - { - _converter.Write(writer, _value, options); - } - } - else if (_jsonTypeInfo != null) - { - JsonSerializer.Serialize(writer, _value, _jsonTypeInfo); - } - else - { - JsonSerializer.Serialize(writer, _value, options); - } - } - } - internal TypeToConvert ConvertJsonElement() { JsonElement element = (JsonElement)(object)_value!; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValueTrimmable.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValueTrimmable.cs new file mode 100644 index 0000000000000..47652c49cc6d4 --- /dev/null +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValueTrimmable.cs @@ -0,0 +1,55 @@ +// 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.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; + +namespace System.Text.Json.Nodes +{ + /// + /// Trim-safe since it either calls the converter directly or calls the JsonSerializer.Serialize(JsonTypeInfo{TValue}). + /// + internal sealed partial class JsonValueTrimmable : JsonValue + { + private readonly JsonTypeInfo? _jsonTypeInfo; + private readonly JsonConverter? _converter; + + public JsonValueTrimmable(TValue value, JsonTypeInfo jsonTypeInfo, JsonNodeOptions? options = null) : base(value, options) + { + _jsonTypeInfo = jsonTypeInfo; + } + + public JsonValueTrimmable(TValue value, JsonConverter converter, JsonNodeOptions? options = null) : base(value, options) + { + _converter = converter; + } + + public override void WriteTo(Utf8JsonWriter writer, JsonSerializerOptions? options = null) + { + if (writer == null) + { + throw new ArgumentNullException(nameof(writer)); + } + + if (_converter != null) + { + options ??= JsonSerializerOptions.s_defaultOptions; + + if (_converter.IsInternalConverterForNumberType) + { + _converter.WriteNumberWithCustomHandling(writer, _value, options.NumberHandling); + } + else + { + _converter.Write(writer, _value, options); + } + } + else + { + Debug.Assert(_jsonTypeInfo != null); + JsonSerializer.Serialize(writer, _value, _jsonTypeInfo); + } + } + } +} diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Node/JsonNodeConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Node/JsonNodeConverter.cs index 058ec499faf40..1e1856ccdaa1a 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Node/JsonNodeConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Node/JsonNodeConverter.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.Text.Json.Nodes; +using System.Text.Json.Serialization.Metadata; namespace System.Text.Json.Serialization.Converters { @@ -81,7 +82,7 @@ public override void Write(Utf8JsonWriter writer, object? value, JsonSerializerO node = new JsonArray(element, options); break; default: - node = new JsonValue(element, options); + node = new JsonValueTrimmable(element, JsonMetadataServices.JsonElementConverter, options); break; } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Node/JsonValueConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Node/JsonValueConverter.cs index 95127d3a14e38..68ae58bb2822b 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Node/JsonValueConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Node/JsonValueConverter.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.Text.Json.Nodes; +using System.Text.Json.Serialization.Metadata; namespace System.Text.Json.Serialization.Converters { @@ -17,7 +18,7 @@ public override void Write(Utf8JsonWriter writer, JsonValue value, JsonSerialize public override JsonValue Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { JsonElement element = JsonElement.ParseValue(ref reader); - JsonValue value = new JsonValue(element, options.GetNodeOptions()); + JsonValue value = new JsonValueTrimmable(element, JsonMetadataServices.JsonElementConverter, options.GetNodeOptions()); return value; } } From be990106be3529093d5dc081c0362c8f0dbd5d35 Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Wed, 19 May 2021 18:09:18 -0500 Subject: [PATCH 3/3] Remove ILLink.Suppressions.xml --- .../src/ILLink/ILLink.Suppressions.xml | 17 ----------------- .../Text/Json/Nodes/JsonValueNotTrimmable.cs | 10 +++++++--- 2 files changed, 7 insertions(+), 20 deletions(-) delete mode 100644 src/libraries/System.Text.Json/src/ILLink/ILLink.Suppressions.xml diff --git a/src/libraries/System.Text.Json/src/ILLink/ILLink.Suppressions.xml b/src/libraries/System.Text.Json/src/ILLink/ILLink.Suppressions.xml deleted file mode 100644 index 420744b19752f..0000000000000 --- a/src/libraries/System.Text.Json/src/ILLink/ILLink.Suppressions.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - ILLink - IL2026 - member - M:System.Text.Json.Nodes.JsonValueNotTrimmable`1.WriteTo(System.Text.Json.Utf8JsonWriter,System.Text.Json.JsonSerializerOptions) - - - ILLink - IL2091 - member - M:System.Text.Json.Nodes.JsonValueNotTrimmable`1.WriteTo(System.Text.Json.Utf8JsonWriter,System.Text.Json.JsonSerializerOptions) - - - diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValueNotTrimmable.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValueNotTrimmable.cs index a45cd48994190..fbe0d7fcea5e7 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValueNotTrimmable.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValueNotTrimmable.cs @@ -1,6 +1,8 @@ // 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.CodeAnalysis; + namespace System.Text.Json.Nodes { /// @@ -8,10 +10,12 @@ namespace System.Text.Json.Nodes /// internal sealed partial class JsonValueNotTrimmable : JsonValue { - public JsonValueNotTrimmable(TValue value, JsonNodeOptions? options = null) : base(value, options) - { - } + public JsonValueNotTrimmable(TValue value, JsonNodeOptions? options = null) : base(value, options) { } + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", + Justification = "The methods used to create this JsonValue are marked RequiresUnreferencedCode.")] + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2091:UnrecognizedReflectionPattern", + Justification = "The methods used to create this JsonValue are marked RequiresUnreferencedCode.")] public override void WriteTo(Utf8JsonWriter writer, JsonSerializerOptions? options = null) { if (writer == null)