Skip to content

Commit f87a2a2

Browse files
Fix handling of top-level nullable type schema generation.
1 parent f3548ef commit f87a2a2

File tree

3 files changed

+34
-8
lines changed

3 files changed

+34
-8
lines changed

src/libraries/System.Text.Json/src/System/Text/Json/Schema/JsonSchemaExporter.cs

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -347,17 +347,30 @@ JsonSchema CompleteSchema(ref GenerationState state, JsonSchema schema)
347347
{
348348
if (schema.Ref is null)
349349
{
350-
// A schema is marked as nullable if either
351-
// 1. We have a schema for a property where either the getter or setter are marked as nullable.
352-
// 2. We have a schema for a reference type, unless we're explicitly treating null-oblivious types as non-nullable.
353-
bool isNullableSchema = propertyInfo != null
354-
? propertyInfo.IsGetNullable || propertyInfo.IsSetNullable
355-
: typeInfo.CanBeNull && !parentPolymorphicTypeIsNonNullable && !state.ExporterOptions.TreatNullObliviousAsNonNullable;
356-
357-
if (isNullableSchema)
350+
if (IsNullableSchema(state.ExporterOptions))
358351
{
359352
schema.MakeNullable();
360353
}
354+
355+
bool IsNullableSchema(JsonSchemaExporterOptions options)
356+
{
357+
// A schema is marked as nullable if either:
358+
// 1. We have a schema for a property where either the getter or setter are marked as nullable.
359+
// 2. We have a schema for a Nullable<T> type.
360+
// 3. We have a schema for a reference type, unless we're explicitly treating null-oblivious types as non-nullable.
361+
362+
if (propertyInfo is not null)
363+
{
364+
return propertyInfo.IsGetNullable || propertyInfo.IsSetNullable;
365+
}
366+
367+
if (typeInfo.IsNullable)
368+
{
369+
return true;
370+
}
371+
372+
return !typeInfo.Type.IsValueType && !parentPolymorphicTypeIsNonNullable && !options.TreatNullObliviousAsNonNullable;
373+
}
361374
}
362375

363376
if (state.ExporterOptions.TransformSchemaNode != null)

src/libraries/System.Text.Json/tests/Common/JsonSchemaExporterTests.TestTypes.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,18 @@ public static IEnumerable<ITestData> GetTestDataCore()
121121
}
122122
""");
123123

124+
yield return new TestData<int?>(
125+
Value: 42,
126+
AdditionalValues: [null],
127+
ExpectedJsonSchema: """{"type":["integer","null"]}""",
128+
Options: new() { TreatNullObliviousAsNonNullable = true });
129+
130+
yield return new TestData<DateTimeOffset?>(
131+
Value: DateTimeOffset.MinValue,
132+
AdditionalValues: [null],
133+
ExpectedJsonSchema: """{"type":["string","null"],"format":"date-time"}""",
134+
Options: new() { TreatNullObliviousAsNonNullable = true });
135+
124136
// User-defined POCOs
125137
yield return new TestData<SimplePoco>(
126138
Value: new() { String = "string", StringNullable = "string", Int = 42, Double = 3.14, Boolean = true },

src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/JsonSchemaExporterTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public sealed partial class JsonSchemaExporterTests_SourceGen()
4141
[JsonSerializable(typeof(ReadOnlyMemory<byte>))]
4242
[JsonSerializable(typeof(DateTime))]
4343
[JsonSerializable(typeof(DateTimeOffset))]
44+
[JsonSerializable(typeof(DateTimeOffset?))]
4445
[JsonSerializable(typeof(TimeSpan))]
4546
#if NET
4647
[JsonSerializable(typeof(DateOnly))]

0 commit comments

Comments
 (0)