From 39153578930bcafa5e1c7ee3105df6a66379c34f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Jun 2026 16:32:42 +0000 Subject: [PATCH 01/12] Initial plan From a46c44eb628b786e775d68a3a45807db6b58ab62 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Jun 2026 17:06:04 +0000 Subject: [PATCH 02/12] Add null branch for anyOf composition schemas of nullable types Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com> --- .../src/System/Text/Json/Schema/JsonSchema.cs | 16 +++++ .../JsonSchemaExporterTests.TestTypes.cs | 62 +++++++++++++++++++ .../Serialization/JsonSchemaExporterTests.cs | 2 + 3 files changed, 80 insertions(+) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchema.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchema.cs index 8ffc12bd077926..fb5c41866e9de1 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchema.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchema.cs @@ -146,6 +146,22 @@ public void MakeNullable() { Type |= JsonSchemaType.Null; } + else if (AnyOf is { } anyOf) + { + // The schema is an "anyOf" composition (e.g. a floating-point type under + // AllowNamedFloatingPointLiterals). Since such schemas carry no top-level + // type keyword, add a dedicated null branch to the union unless one of the + // existing branches already permits null. + foreach (JsonSchema branch in anyOf) + { + if ((branch.Type & JsonSchemaType.Null) != 0) + { + return; + } + } + + anyOf.Add(new JsonSchema { Type = JsonSchemaType.Null }); + } } public JsonNode ToJsonNode(JsonSchemaExporterOptions options) diff --git a/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs b/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs index c4c14ef1c1b0f8..e1e8c4a85e89bc 100644 --- a/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs +++ b/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs @@ -285,6 +285,62 @@ public static IEnumerable GetTestDataCore() } """); + // Regression test for https://github.com/dotnet/runtime/issues/129432 + // Nullable floating-point types under AllowNamedFloatingPointLiterals must retain the null branch. + yield return new TestData( + Value: 3.14, + AdditionalValues: [null, double.NaN, double.PositiveInfinity, double.NegativeInfinity], + ExpectedJsonSchema: """ + { + "anyOf": [ + { "type": "number" }, + { "enum": ["NaN", "Infinity", "-Infinity"] }, + { "type": "null" } + ] + } + """, + SerializerOptions: new() { NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals }); + + yield return new TestData( + Value: 1.2f, + AdditionalValues: [null, float.NaN, float.PositiveInfinity, float.NegativeInfinity], + ExpectedJsonSchema: """ + { + "anyOf": [ + { "type": "number" }, + { "enum": ["NaN", "Infinity", "-Infinity"] }, + { "type": "null" } + ] + } + """, + SerializerOptions: new() { NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals }); + + yield return new TestData( + Value: new() { Latitude = 3.14, Longitude = 1.2f }, + AdditionalValues: [new() { Latitude = null, Longitude = null }], + ExpectedJsonSchema: """ + { + "type": ["object","null"], + "properties": { + "Latitude": { + "anyOf": [ + { "type": "number" }, + { "enum": ["NaN", "Infinity", "-Infinity"] }, + { "type": "null" } + ] + }, + "Longitude": { + "anyOf": [ + { "type": "number" }, + { "enum": ["NaN", "Infinity", "-Infinity"] }, + { "type": "null" } + ] + } + } + } + """, + SerializerOptions: new() { NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals }); + yield return new TestData( Value: new() { Value = 1, Next = new() { Value = 2, Next = new() { Value = 3 } } }, AdditionalValues: [new() { Value = 1, Next = null }], @@ -1290,6 +1346,12 @@ public class PocoWithCustomNumberHandlingOnProperties public decimal DecimalAllowingFloatingPointLiteralsAndReadingFromString { get; set; } } + public class PocoWithNullableFloatingPoint + { + public double? Latitude { get; set; } + public float? Longitude { get; set; } + } + public class PocoWithRecursiveMembers { public int Value { get; init; } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/JsonSchemaExporterTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/JsonSchemaExporterTests.cs index 01558bb3658642..f5d8db97d72023 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/JsonSchemaExporterTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/JsonSchemaExporterTests.cs @@ -72,6 +72,7 @@ public sealed partial class JsonSchemaExporterTests_SourceGen() [JsonSerializable(typeof(bool?))] [JsonSerializable(typeof(int?))] [JsonSerializable(typeof(double?))] + [JsonSerializable(typeof(float?))] [JsonSerializable(typeof(Guid?))] [JsonSerializable(typeof(JsonElement?))] [JsonSerializable(typeof(IntEnum?))] @@ -87,6 +88,7 @@ public sealed partial class JsonSchemaExporterTests_SourceGen() [JsonSerializable(typeof(PocoWithCustomNaming))] [JsonSerializable(typeof(PocoWithCustomNumberHandling))] [JsonSerializable(typeof(PocoWithCustomNumberHandlingOnProperties))] + [JsonSerializable(typeof(PocoWithNullableFloatingPoint))] [JsonSerializable(typeof(PocoWithRecursiveMembers))] [JsonSerializable(typeof(PocoWithRecursiveCollectionElement))] [JsonSerializable(typeof(PocoWithRecursiveDictionaryValue))] From 3279084a8faa8785d9d5c1663727c4b92f70ab24 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 18 Jun 2026 13:22:38 +0000 Subject: [PATCH 03/12] Fold null into first typed anyOf branch instead of adding a null branch Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com> --- .../src/System/Text/Json/Schema/JsonSchema.cs | 19 +++++++++++++----- .../JsonSchemaExporterTests.TestTypes.cs | 20 ++++++++----------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchema.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchema.cs index fb5c41866e9de1..a3c3d36d41755f 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchema.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchema.cs @@ -148,19 +148,28 @@ public void MakeNullable() } else if (AnyOf is { } anyOf) { - // The schema is an "anyOf" composition (e.g. a floating-point type under - // AllowNamedFloatingPointLiterals). Since such schemas carry no top-level - // type keyword, add a dedicated null branch to the union unless one of the - // existing branches already permits null. + // The schema is an "anyOf" composition with no top-level type keyword + // (e.g. an IEEE floating-point type under AllowNamedFloatingPointLiterals). + // Fold the null type into the first branch that carries a concrete type, + // unless one of the branches already permits null. + JsonSchema? firstTypedBranch = null; foreach (JsonSchema branch in anyOf) { if ((branch.Type & JsonSchemaType.Null) != 0) { return; } + + if (firstTypedBranch is null && branch.Type is not JsonSchemaType.Any) + { + firstTypedBranch = branch; + } } - anyOf.Add(new JsonSchema { Type = JsonSchemaType.Null }); + if (firstTypedBranch is not null) + { + firstTypedBranch.Type |= JsonSchemaType.Null; + } } } diff --git a/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs b/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs index e1e8c4a85e89bc..601196b2104df2 100644 --- a/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs +++ b/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs @@ -293,9 +293,8 @@ public static IEnumerable GetTestDataCore() ExpectedJsonSchema: """ { "anyOf": [ - { "type": "number" }, - { "enum": ["NaN", "Infinity", "-Infinity"] }, - { "type": "null" } + { "type": ["number","null"] }, + { "enum": ["NaN", "Infinity", "-Infinity"] } ] } """, @@ -307,9 +306,8 @@ public static IEnumerable GetTestDataCore() ExpectedJsonSchema: """ { "anyOf": [ - { "type": "number" }, - { "enum": ["NaN", "Infinity", "-Infinity"] }, - { "type": "null" } + { "type": ["number","null"] }, + { "enum": ["NaN", "Infinity", "-Infinity"] } ] } """, @@ -324,16 +322,14 @@ public static IEnumerable GetTestDataCore() "properties": { "Latitude": { "anyOf": [ - { "type": "number" }, - { "enum": ["NaN", "Infinity", "-Infinity"] }, - { "type": "null" } + { "type": ["number","null"] }, + { "enum": ["NaN", "Infinity", "-Infinity"] } ] }, "Longitude": { "anyOf": [ - { "type": "number" }, - { "enum": ["NaN", "Infinity", "-Infinity"] }, - { "type": "null" } + { "type": ["number","null"] }, + { "enum": ["NaN", "Infinity", "-Infinity"] } ] } } From c81c58a3e12834a918134ed6e94a9fd8edaba399 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 18 Jun 2026 16:01:50 +0000 Subject: [PATCH 04/12] Handle nullable floating-point anyOf in NullableElementConverter path, revert MakeNullable Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com> --- .../src/System/Text/Json/Schema/JsonSchema.cs | 25 ------------------- .../Text/Json/Schema/JsonSchemaExporter.cs | 14 +++++++++++ 2 files changed, 14 insertions(+), 25 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchema.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchema.cs index a3c3d36d41755f..8ffc12bd077926 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchema.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchema.cs @@ -146,31 +146,6 @@ public void MakeNullable() { Type |= JsonSchemaType.Null; } - else if (AnyOf is { } anyOf) - { - // The schema is an "anyOf" composition with no top-level type keyword - // (e.g. an IEEE floating-point type under AllowNamedFloatingPointLiterals). - // Fold the null type into the first branch that carries a concrete type, - // unless one of the branches already permits null. - JsonSchema? firstTypedBranch = null; - foreach (JsonSchema branch in anyOf) - { - if ((branch.Type & JsonSchemaType.Null) != 0) - { - return; - } - - if (firstTypedBranch is null && branch.Type is not JsonSchemaType.Any) - { - firstTypedBranch = branch; - } - } - - if (firstTypedBranch is not null) - { - firstTypedBranch.Type |= JsonSchemaType.Null; - } - } } public JsonNode ToJsonNode(JsonSchemaExporterOptions options) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs index 9cb3a3efc27fb0..52ffe600e399d8 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs @@ -187,6 +187,20 @@ private static JsonSchema MapJsonSchemaCore( Debug.Assert(elementTypeInfo.Type.IsEnum, "The enum keyword should only be populated by schemas for enum types."); schema.Enum.Add(null); // Append null to the enum array. } + else if (schema.AnyOf is { } anyOf) + { + // The element schema is an "anyOf" composition, which for a nullable value type + // can only originate from an IEEE floating-point type formatted under + // AllowNamedFloatingPointLiterals. Fold the null type into the numeric branch. + foreach (JsonSchema branch in anyOf) + { + if (branch.Type is not JsonSchemaType.Any) + { + branch.Type |= JsonSchemaType.Null; + break; + } + } + } return CompleteSchema(ref state, schema); } From 5fa9d6eb3a551604c6dfe1b17f61ea5b15994884 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 18 Jun 2026 17:20:41 +0000 Subject: [PATCH 05/12] Append null to enum branch of nullable floating-point anyOf schema Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com> --- .../Text/Json/Schema/JsonSchemaExporter.cs | 7 ++++--- .../Common/JsonSchemaExporterTests.TestTypes.cs | 16 ++++++++-------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs index 52ffe600e399d8..57db7371b268eb 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs @@ -191,12 +191,13 @@ private static JsonSchema MapJsonSchemaCore( { // The element schema is an "anyOf" composition, which for a nullable value type // can only originate from an IEEE floating-point type formatted under - // AllowNamedFloatingPointLiterals. Fold the null type into the numeric branch. + // AllowNamedFloatingPointLiterals. Append null to the enum branch listing the + // named floating-point literals, mirroring the enum handling above. foreach (JsonSchema branch in anyOf) { - if (branch.Type is not JsonSchemaType.Any) + if (branch.Enum != null) { - branch.Type |= JsonSchemaType.Null; + branch.Enum.Add(null); // Append null to the enum array. break; } } diff --git a/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs b/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs index 601196b2104df2..2bf8980a2fb606 100644 --- a/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs +++ b/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs @@ -293,8 +293,8 @@ public static IEnumerable GetTestDataCore() ExpectedJsonSchema: """ { "anyOf": [ - { "type": ["number","null"] }, - { "enum": ["NaN", "Infinity", "-Infinity"] } + { "type": "number" }, + { "enum": ["NaN", "Infinity", "-Infinity", null] } ] } """, @@ -306,8 +306,8 @@ public static IEnumerable GetTestDataCore() ExpectedJsonSchema: """ { "anyOf": [ - { "type": ["number","null"] }, - { "enum": ["NaN", "Infinity", "-Infinity"] } + { "type": "number" }, + { "enum": ["NaN", "Infinity", "-Infinity", null] } ] } """, @@ -322,14 +322,14 @@ public static IEnumerable GetTestDataCore() "properties": { "Latitude": { "anyOf": [ - { "type": ["number","null"] }, - { "enum": ["NaN", "Infinity", "-Infinity"] } + { "type": "number" }, + { "enum": ["NaN", "Infinity", "-Infinity", null] } ] }, "Longitude": { "anyOf": [ - { "type": ["number","null"] }, - { "enum": ["NaN", "Infinity", "-Infinity"] } + { "type": "number" }, + { "enum": ["NaN", "Infinity", "-Infinity", null] } ] } } From 9fd1801a31f115f4aced3062388922825e130c21 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 19 Jun 2026 07:33:54 +0000 Subject: [PATCH 06/12] Use is-pattern for enum branch null append in nullable float schema Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com> --- .../src/System/Text/Json/Schema/JsonSchemaExporter.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs index 57db7371b268eb..859742a5aaf898 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs @@ -195,9 +195,9 @@ private static JsonSchema MapJsonSchemaCore( // named floating-point literals, mirroring the enum handling above. foreach (JsonSchema branch in anyOf) { - if (branch.Enum != null) + if (branch.Enum is { } enumValues) { - branch.Enum.Add(null); // Append null to the enum array. + enumValues.Add(null); // Append null to the enum array. break; } } From a272333a57711a87dd64e0ecae632b335dabf79a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 19 Jun 2026 16:01:39 +0000 Subject: [PATCH 07/12] Fix nullable float anyOf nullability to use type branch Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com> --- .../Text/Json/Schema/JsonSchemaExporter.cs | 34 ++++++++++++------- .../JsonSchemaExporterTests.TestTypes.cs | 16 ++++----- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs index 859742a5aaf898..12bb1998f632a4 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs @@ -182,25 +182,35 @@ private static JsonSchema MapJsonSchemaCore( JsonTypeInfo elementTypeInfo = typeInfo.Options.GetTypeInfo(elementConverter.Type!); schema = MapJsonSchemaCore(ref state, elementTypeInfo, customConverter: elementConverter, cacheResult: false); - if (schema.Enum != null) + if (schema.AnyOf is { } anyOf) { - Debug.Assert(elementTypeInfo.Type.IsEnum, "The enum keyword should only be populated by schemas for enum types."); - schema.Enum.Add(null); // Append null to the enum array. - } - else if (schema.AnyOf is { } anyOf) - { - // The element schema is an "anyOf" composition, which for a nullable value type - // can only originate from an IEEE floating-point type formatted under - // AllowNamedFloatingPointLiterals. Append null to the enum branch listing the - // named floating-point literals, mirroring the enum handling above. + // The element schema is an "anyOf" composition, which for nullable value types + // should only originate from IEEE floating-point types using + // AllowNamedFloatingPointLiterals. + Debug.Assert((effectiveNumberHandling & JsonNumberHandling.AllowNamedFloatingPointLiterals) != 0 && + (elementTypeInfo.Type == typeof(double) || elementTypeInfo.Type == typeof(float) +#if NET + || elementTypeInfo.Type == typeof(Half) +#endif + )); + + bool foundNumberBranch = false; foreach (JsonSchema branch in anyOf) { - if (branch.Enum is { } enumValues) + if ((branch.Type & JsonSchemaType.Number) != 0) { - enumValues.Add(null); // Append null to the enum array. + branch.Type |= JsonSchemaType.Null; + foundNumberBranch = true; break; } } + + Debug.Assert(foundNumberBranch); + } + else if (schema.Enum != null) + { + Debug.Assert(elementTypeInfo.Type.IsEnum, "The enum keyword should only be populated by schemas for enum types."); + schema.Enum.Add(null); // Append null to the enum array. } return CompleteSchema(ref state, schema); diff --git a/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs b/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs index 2bf8980a2fb606..04ac3933252783 100644 --- a/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs +++ b/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs @@ -293,8 +293,8 @@ public static IEnumerable GetTestDataCore() ExpectedJsonSchema: """ { "anyOf": [ - { "type": "number" }, - { "enum": ["NaN", "Infinity", "-Infinity", null] } + { "type": ["number", "null"] }, + { "enum": ["NaN", "Infinity", "-Infinity"] } ] } """, @@ -306,8 +306,8 @@ public static IEnumerable GetTestDataCore() ExpectedJsonSchema: """ { "anyOf": [ - { "type": "number" }, - { "enum": ["NaN", "Infinity", "-Infinity", null] } + { "type": ["number", "null"] }, + { "enum": ["NaN", "Infinity", "-Infinity"] } ] } """, @@ -322,14 +322,14 @@ public static IEnumerable GetTestDataCore() "properties": { "Latitude": { "anyOf": [ - { "type": "number" }, - { "enum": ["NaN", "Infinity", "-Infinity", null] } + { "type": ["number", "null"] }, + { "enum": ["NaN", "Infinity", "-Infinity"] } ] }, "Longitude": { "anyOf": [ - { "type": "number" }, - { "enum": ["NaN", "Infinity", "-Infinity", null] } + { "type": ["number", "null"] }, + { "enum": ["NaN", "Infinity", "-Infinity"] } ] } } From 206189495d31939d15c936a9b8b2c23be6d7198f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 19 Jun 2026 16:24:03 +0000 Subject: [PATCH 08/12] Add safe fallback and Half? test coverage for nullable float schema nullability Co-authored-by: eiriktsarpalis <10833894+eiriktsarpalis@users.noreply.github.com> --- .../Text/Json/Schema/JsonSchemaExporter.cs | 28 +++++++++++-------- .../JsonSchemaExporterTests.TestTypes.cs | 15 ++++++++++ .../Serialization/JsonSchemaExporterTests.cs | 3 ++ 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs index 12bb1998f632a4..bc5b5eccfa5038 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs @@ -184,16 +184,9 @@ private static JsonSchema MapJsonSchemaCore( if (schema.AnyOf is { } anyOf) { - // The element schema is an "anyOf" composition, which for nullable value types - // should only originate from IEEE floating-point types using - // AllowNamedFloatingPointLiterals. - Debug.Assert((effectiveNumberHandling & JsonNumberHandling.AllowNamedFloatingPointLiterals) != 0 && - (elementTypeInfo.Type == typeof(double) || elementTypeInfo.Type == typeof(float) -#if NET - || elementTypeInfo.Type == typeof(Half) -#endif - )); - + // The element schema is an "anyOf" composition. For nullable value types, + // this typically originates from IEEE floating-point types using + // AllowNamedFloatingPointLiterals, though other internal wrappers may also use anyOf. bool foundNumberBranch = false; foreach (JsonSchema branch in anyOf) { @@ -205,7 +198,20 @@ private static JsonSchema MapJsonSchemaCore( } } - Debug.Assert(foundNumberBranch); + if (!foundNumberBranch) + { + // If no numeric branch was found, append a standalone null type to ensure nullability. + // For IEEE floating-point types, we expect a numeric branch to be present. + Debug.Assert((effectiveNumberHandling & JsonNumberHandling.AllowNamedFloatingPointLiterals) == 0 || + (elementTypeInfo.Type != typeof(double) && elementTypeInfo.Type != typeof(float) +#if NET + && elementTypeInfo.Type != typeof(Half) +#endif + ), + "Expected a numeric branch for IEEE floating-point types with AllowNamedFloatingPointLiterals."); + + anyOf.Add(JsonSchema.CreateTrue().MakeNullable()); + } } else if (schema.Enum != null) { diff --git a/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs b/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs index 04ac3933252783..065f18e501d5ec 100644 --- a/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs +++ b/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs @@ -313,6 +313,21 @@ public static IEnumerable GetTestDataCore() """, SerializerOptions: new() { NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals }); +#if NET + yield return new TestData( + Value: (Half)1.5, + AdditionalValues: [null, Half.NaN, Half.PositiveInfinity, Half.NegativeInfinity], + ExpectedJsonSchema: """ + { + "anyOf": [ + { "type": ["number", "null"] }, + { "enum": ["NaN", "Infinity", "-Infinity"] } + ] + } + """, + SerializerOptions: new() { NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals }); +#endif + yield return new TestData( Value: new() { Latitude = 3.14, Longitude = 1.2f }, AdditionalValues: [new() { Latitude = null, Longitude = null }], diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/JsonSchemaExporterTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/JsonSchemaExporterTests.cs index f5d8db97d72023..f4cf65cb00a8b9 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/JsonSchemaExporterTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/JsonSchemaExporterTests.cs @@ -73,6 +73,9 @@ public sealed partial class JsonSchemaExporterTests_SourceGen() [JsonSerializable(typeof(int?))] [JsonSerializable(typeof(double?))] [JsonSerializable(typeof(float?))] +#if NET + [JsonSerializable(typeof(Half?))] +#endif [JsonSerializable(typeof(Guid?))] [JsonSerializable(typeof(JsonElement?))] [JsonSerializable(typeof(IntEnum?))] From 039aee68ef31de46f5840f95958e04cd708df254 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 19 Jun 2026 16:35:51 +0000 Subject: [PATCH 09/12] Fix safe fallback to use new JsonSchema with Type = Null Co-authored-by: eiriktsarpalis <10833894+eiriktsarpalis@users.noreply.github.com> --- .../src/System/Text/Json/Schema/JsonSchemaExporter.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs index bc5b5eccfa5038..61eb036facca27 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs @@ -209,8 +209,8 @@ private static JsonSchema MapJsonSchemaCore( #endif ), "Expected a numeric branch for IEEE floating-point types with AllowNamedFloatingPointLiterals."); - - anyOf.Add(JsonSchema.CreateTrue().MakeNullable()); + + anyOf.Add(new JsonSchema { Type = JsonSchemaType.Null }); } } else if (schema.Enum != null) From 9ebaa0bf21a237d4bb323cbf44bb99a52ec09d58 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 19 Jun 2026 17:34:14 +0000 Subject: [PATCH 10/12] Use IsIeeeFloatingPointConverter property instead of type checks Introduced a virtual property `IsIeeeFloatingPointConverter` on `JsonConverter`, overridden to `true` in `DoubleConverter`, `SingleConverter`, and `HalfConverter`. Updated `JsonSchemaExporter` to check this property instead of performing brittle element type checks, preventing false positives from nullable struct unions. Replaced the boolean foundNumberBranch with a Debug.Assert that checks the list before iteration. Added test coverage for nullable struct unions to ensure nullability is preserved without affecting IEEE floating-point schema generation. Co-authored-by: eiriktsarpalis <16040868+eiriktsarpalis@users.noreply.github.com> --- .../Text/Json/Schema/JsonSchemaExporter.cs | 31 ++++++-------- .../Converters/Value/DoubleConverter.cs | 2 + .../Converters/Value/HalfConverter.cs | 2 + .../Converters/Value/SingleConverter.cs | 2 + .../Text/Json/Serialization/JsonConverter.cs | 7 ++++ .../JsonSchemaExporterTests.TestTypes.cs | 40 +++++++++++++++++++ .../Serialization/JsonSchemaExporterTests.cs | 3 ++ 7 files changed, 69 insertions(+), 18 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs index 61eb036facca27..cddbf0d8f7a70d 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs @@ -187,29 +187,24 @@ private static JsonSchema MapJsonSchemaCore( // The element schema is an "anyOf" composition. For nullable value types, // this typically originates from IEEE floating-point types using // AllowNamedFloatingPointLiterals, though other internal wrappers may also use anyOf. - bool foundNumberBranch = false; - foreach (JsonSchema branch in anyOf) + // Only fold null into the numeric branch for IEEE floating-point converters. + if (elementConverter.IsIeeeFloatingPointConverter) { - if ((branch.Type & JsonSchemaType.Number) != 0) + Debug.Assert(anyOf.Exists(b => (b.Type & JsonSchemaType.Number) != 0), + "IEEE floating-point converters with AllowNamedFloatingPointLiterals should have a numeric branch."); + + foreach (JsonSchema branch in anyOf) { - branch.Type |= JsonSchemaType.Null; - foundNumberBranch = true; - break; + if ((branch.Type & JsonSchemaType.Number) != 0) + { + branch.Type |= JsonSchemaType.Null; + break; + } } } - - if (!foundNumberBranch) + else { - // If no numeric branch was found, append a standalone null type to ensure nullability. - // For IEEE floating-point types, we expect a numeric branch to be present. - Debug.Assert((effectiveNumberHandling & JsonNumberHandling.AllowNamedFloatingPointLiterals) == 0 || - (elementTypeInfo.Type != typeof(double) && elementTypeInfo.Type != typeof(float) -#if NET - && elementTypeInfo.Type != typeof(Half) -#endif - ), - "Expected a numeric branch for IEEE floating-point types with AllowNamedFloatingPointLiterals."); - + // For other anyOf schemas (e.g., nullable struct unions), append a standalone null type. anyOf.Add(new JsonSchema { Type = JsonSchemaType.Null }); } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/DoubleConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/DoubleConverter.cs index 0f45e0631a8222..a80e2427a86bbd 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/DoubleConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/DoubleConverter.cs @@ -14,6 +14,8 @@ public DoubleConverter() IsInternalConverterForNumberType = true; } + internal override bool IsIeeeFloatingPointConverter => true; + public override double Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (options?.NumberHandling is not null and not JsonNumberHandling.Strict) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/HalfConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/HalfConverter.cs index a1eae208c3ddad..b94fb2ebb7c924 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/HalfConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/HalfConverter.cs @@ -19,6 +19,8 @@ public HalfConverter() IsInternalConverterForNumberType = true; } + internal override bool IsIeeeFloatingPointConverter => true; + public override Half Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (options?.NumberHandling is not null and not JsonNumberHandling.Strict) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/SingleConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/SingleConverter.cs index 225fb08b892524..5cbdf5fbd80b45 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/SingleConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/SingleConverter.cs @@ -15,6 +15,8 @@ public SingleConverter() IsInternalConverterForNumberType = true; } + internal override bool IsIeeeFloatingPointConverter => true; + public override float Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (options?.NumberHandling is not null and not JsonNumberHandling.Strict) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverter.cs index e2bd29a8dff101..8f8efccd306b5f 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverter.cs @@ -175,6 +175,13 @@ internal JsonConverter CreateCastingConverter() /// internal bool IsValueType { get; init; } + /// + /// Indicates whether this converter handles IEEE 754 floating-point types + /// (double, float, Half) that may emit anyOf schemas with named floating-point + /// literals under AllowNamedFloatingPointLiterals. + /// + internal virtual bool IsIeeeFloatingPointConverter => false; + /// /// Whether the converter is built-in. /// diff --git a/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs b/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs index 065f18e501d5ec..56419cfb168405 100644 --- a/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs +++ b/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs @@ -352,6 +352,31 @@ public static IEnumerable GetTestDataCore() """, SerializerOptions: new() { NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals }); + // Test nullable struct union to ensure nullability is preserved with anyOf + yield return new TestData( + Value: new StructLeft("test"), + AdditionalValues: [new StructRight(42), null], + ExpectedJsonSchema: """ + { + "type": ["object","null"], + "required": ["$type"], + "anyOf": [ + { + "properties": { + "$type": { "const": "left" }, + "Value": { "type": "string" } + } + }, + { + "properties": { + "$type": { "const": "right" }, + "Value": { "type": "integer" } + } + } + ] + } + """); + yield return new TestData( Value: new() { Value = 1, Next = new() { Value = 2, Next = new() { Value = 3 } } }, AdditionalValues: [new() { Value = 1, Next = null }], @@ -1586,6 +1611,21 @@ public record Left(string value) : DiscriminatedUnion; public record Right(int value) : DiscriminatedUnion; } + [JsonPolymorphic] + [JsonDerivedType(typeof(StructLeft), "left")] + [JsonDerivedType(typeof(StructRight), "right")] + public interface IStructDiscriminatedUnion; + + public struct StructLeft(string Value) : IStructDiscriminatedUnion + { + public string Value { get; set; } = Value; + } + + public struct StructRight(int Value) : IStructDiscriminatedUnion + { + public int Value { get; set; } = Value; + } + public class PocoCombiningPolymorphicTypeAndDerivedTypes { public PocoWithPolymorphism PolymorphicValue { get; set; } = new PocoWithPolymorphism.DerivedPocoNoDiscriminator { DerivedValue = "derived" }; diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/JsonSchemaExporterTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/JsonSchemaExporterTests.cs index f4cf65cb00a8b9..1df309194f1ef0 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/JsonSchemaExporterTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/JsonSchemaExporterTests.cs @@ -111,6 +111,9 @@ public sealed partial class JsonSchemaExporterTests_SourceGen() [JsonSerializable(typeof(GenericPocoWithNullableConstructorParameter))] [JsonSerializable(typeof(PocoWithPolymorphism))] [JsonSerializable(typeof(DiscriminatedUnion))] + [JsonSerializable(typeof(IStructDiscriminatedUnion))] + [JsonSerializable(typeof(StructLeft))] + [JsonSerializable(typeof(StructRight))] [JsonSerializable(typeof(NonAbstractClassWithSingleDerivedType))] [JsonSerializable(typeof(PocoCombiningPolymorphicTypeAndDerivedTypes))] [JsonSerializable(typeof(ClassWithComponentModelAttributes))] From 331bf8e7aad59b2c8a89b7c3034ae35ce529cbe0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 22 Jun 2026 15:16:45 +0000 Subject: [PATCH 11/12] Replace invalid struct union test with proper C# union type Replaced the IStructDiscriminatedUnion polymorphic interface test with a proper C# union type (MyUnion(int, string)) as requested. The union type test validates that nullable struct unions preserve nullability in anyOf schemas without relying on the IEEE floating-point converter path. Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com> --- .../JsonSchemaExporterTests.TestTypes.cs | 37 +++---------------- .../Serialization/JsonSchemaExporterTests.cs | 4 +- 2 files changed, 7 insertions(+), 34 deletions(-) diff --git a/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs b/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs index 56419cfb168405..eeab511aa74ecf 100644 --- a/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs +++ b/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs @@ -353,26 +353,14 @@ public static IEnumerable GetTestDataCore() SerializerOptions: new() { NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals }); // Test nullable struct union to ensure nullability is preserved with anyOf - yield return new TestData( - Value: new StructLeft("test"), - AdditionalValues: [new StructRight(42), null], + yield return new TestData( + Value: 42, + AdditionalValues: ["test", null], ExpectedJsonSchema: """ { - "type": ["object","null"], - "required": ["$type"], "anyOf": [ - { - "properties": { - "$type": { "const": "left" }, - "Value": { "type": "string" } - } - }, - { - "properties": { - "$type": { "const": "right" }, - "Value": { "type": "integer" } - } - } + { "type": ["integer","null"] }, + { "type": "string" } ] } """); @@ -1611,20 +1599,7 @@ public record Left(string value) : DiscriminatedUnion; public record Right(int value) : DiscriminatedUnion; } - [JsonPolymorphic] - [JsonDerivedType(typeof(StructLeft), "left")] - [JsonDerivedType(typeof(StructRight), "right")] - public interface IStructDiscriminatedUnion; - - public struct StructLeft(string Value) : IStructDiscriminatedUnion - { - public string Value { get; set; } = Value; - } - - public struct StructRight(int Value) : IStructDiscriminatedUnion - { - public int Value { get; set; } = Value; - } + public union MyUnion(int, string); public class PocoCombiningPolymorphicTypeAndDerivedTypes { diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/JsonSchemaExporterTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/JsonSchemaExporterTests.cs index 1df309194f1ef0..87f53d9195f26a 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/JsonSchemaExporterTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/JsonSchemaExporterTests.cs @@ -111,9 +111,7 @@ public sealed partial class JsonSchemaExporterTests_SourceGen() [JsonSerializable(typeof(GenericPocoWithNullableConstructorParameter))] [JsonSerializable(typeof(PocoWithPolymorphism))] [JsonSerializable(typeof(DiscriminatedUnion))] - [JsonSerializable(typeof(IStructDiscriminatedUnion))] - [JsonSerializable(typeof(StructLeft))] - [JsonSerializable(typeof(StructRight))] + [JsonSerializable(typeof(MyUnion?))] [JsonSerializable(typeof(NonAbstractClassWithSingleDerivedType))] [JsonSerializable(typeof(PocoCombiningPolymorphicTypeAndDerivedTypes))] [JsonSerializable(typeof(ClassWithComponentModelAttributes))] From 096c7aff3644209b81a0ac82a6a3c71037e55f5a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 22 Jun 2026 16:03:37 +0000 Subject: [PATCH 12/12] Remove dead else branch in nullable anyOf handling and strengthen IEEE float check Following review feedback, the nullable anyOf handling now: 1. Only executes for IEEE floating-point converters with AllowNamedFloatingPointLiterals 2. Asserts that anyOf schema exists (as it always should for this specific case) 3. Removes the unreachable else branch that was never hit by any test case The MyUnion? test case and type declaration have been removed because union schema generation handles nullable cases internally via caseInfo.IsNullable, so the nullable wrapper code path is never exercised for unions. Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com> --- .../Text/Json/Schema/JsonSchemaExporter.cs | 34 ++++++++----------- .../JsonSchemaExporterTests.TestTypes.cs | 15 -------- .../Serialization/JsonSchemaExporterTests.cs | 1 - 3 files changed, 14 insertions(+), 36 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs index cddbf0d8f7a70d..1ac5814543c963 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs @@ -182,31 +182,25 @@ private static JsonSchema MapJsonSchemaCore( JsonTypeInfo elementTypeInfo = typeInfo.Options.GetTypeInfo(elementConverter.Type!); schema = MapJsonSchemaCore(ref state, elementTypeInfo, customConverter: elementConverter, cacheResult: false); - if (schema.AnyOf is { } anyOf) + if (elementConverter.IsIeeeFloatingPointConverter && + (effectiveNumberHandling & JsonNumberHandling.AllowNamedFloatingPointLiterals) != 0) { - // The element schema is an "anyOf" composition. For nullable value types, - // this typically originates from IEEE floating-point types using - // AllowNamedFloatingPointLiterals, though other internal wrappers may also use anyOf. - // Only fold null into the numeric branch for IEEE floating-point converters. - if (elementConverter.IsIeeeFloatingPointConverter) - { - Debug.Assert(anyOf.Exists(b => (b.Type & JsonSchemaType.Number) != 0), - "IEEE floating-point converters with AllowNamedFloatingPointLiterals should have a numeric branch."); + // IEEE floating-point types with AllowNamedFloatingPointLiterals generate an anyOf schema. + // Fold null into the numeric branch to preserve nullability for nullable wrappers. + Debug.Assert(schema.AnyOf is not null, "IEEE floating-point types with AllowNamedFloatingPointLiterals should generate an anyOf schema."); + + List anyOf = schema.AnyOf; + Debug.Assert(anyOf.Exists(b => (b.Type & JsonSchemaType.Number) != 0), + "IEEE floating-point anyOf schema should have a numeric branch."); - foreach (JsonSchema branch in anyOf) + foreach (JsonSchema branch in anyOf) + { + if ((branch.Type & JsonSchemaType.Number) != 0) { - if ((branch.Type & JsonSchemaType.Number) != 0) - { - branch.Type |= JsonSchemaType.Null; - break; - } + branch.Type |= JsonSchemaType.Null; + break; } } - else - { - // For other anyOf schemas (e.g., nullable struct unions), append a standalone null type. - anyOf.Add(new JsonSchema { Type = JsonSchemaType.Null }); - } } else if (schema.Enum != null) { diff --git a/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs b/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs index eeab511aa74ecf..065f18e501d5ec 100644 --- a/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs +++ b/src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs @@ -352,19 +352,6 @@ public static IEnumerable GetTestDataCore() """, SerializerOptions: new() { NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals }); - // Test nullable struct union to ensure nullability is preserved with anyOf - yield return new TestData( - Value: 42, - AdditionalValues: ["test", null], - ExpectedJsonSchema: """ - { - "anyOf": [ - { "type": ["integer","null"] }, - { "type": "string" } - ] - } - """); - yield return new TestData( Value: new() { Value = 1, Next = new() { Value = 2, Next = new() { Value = 3 } } }, AdditionalValues: [new() { Value = 1, Next = null }], @@ -1599,8 +1586,6 @@ public record Left(string value) : DiscriminatedUnion; public record Right(int value) : DiscriminatedUnion; } - public union MyUnion(int, string); - public class PocoCombiningPolymorphicTypeAndDerivedTypes { public PocoWithPolymorphism PolymorphicValue { get; set; } = new PocoWithPolymorphism.DerivedPocoNoDiscriminator { DerivedValue = "derived" }; diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/JsonSchemaExporterTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/JsonSchemaExporterTests.cs index 87f53d9195f26a..f4cf65cb00a8b9 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/JsonSchemaExporterTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/JsonSchemaExporterTests.cs @@ -111,7 +111,6 @@ public sealed partial class JsonSchemaExporterTests_SourceGen() [JsonSerializable(typeof(GenericPocoWithNullableConstructorParameter))] [JsonSerializable(typeof(PocoWithPolymorphism))] [JsonSerializable(typeof(DiscriminatedUnion))] - [JsonSerializable(typeof(MyUnion?))] [JsonSerializable(typeof(NonAbstractClassWithSingleDerivedType))] [JsonSerializable(typeof(PocoCombiningPolymorphicTypeAndDerivedTypes))] [JsonSerializable(typeof(ClassWithComponentModelAttributes))]