@@ -78,22 +78,22 @@ private static JsonSchema MapJsonSchemaCore(
78
78
79
79
if ( cacheResult && state . TryPushType ( typeInfo , propertyInfo , out string ? existingJsonPointer ) )
80
80
{
81
- // Schema for type has already been generated , return a reference to it .
81
+ // We're generating the schema of a recursive type , return a reference pointing to the outermost schema .
82
82
return CompleteSchema ( ref state , new JsonSchema { Ref = existingJsonPointer } ) ;
83
83
}
84
84
85
85
JsonConverter effectiveConverter = customConverter ?? typeInfo . Converter ;
86
86
JsonNumberHandling effectiveNumberHandling = customNumberHandling ?? typeInfo . NumberHandling ?? typeInfo . Options . NumberHandling ;
87
87
if ( effectiveConverter . GetSchema ( effectiveNumberHandling ) is { } schema )
88
88
{
89
+ // A schema has been provided by the converter.
89
90
return CompleteSchema ( ref state , schema ) ;
90
91
}
91
92
92
93
if ( parentPolymorphicType is null && typeInfo . PolymorphismOptions is { DerivedTypes . Count : > 0 } polyOptions )
93
94
{
94
95
// This is the base type of a polymorphic type hierarchy. The schema for this type
95
96
// will include an "anyOf" property with the schemas for all derived types.
96
-
97
97
string typeDiscriminatorKey = polyOptions . TypeDiscriminatorPropertyName ;
98
98
List < JsonDerivedType > derivedTypes = new ( polyOptions . DerivedTypes ) ;
99
99
@@ -141,7 +141,7 @@ private static JsonSchema MapJsonSchemaCore(
141
141
142
142
state . PopSchemaNode ( ) ;
143
143
144
- // Determine if all derived types have the same schema type.
144
+ // Determine if all derived schemas have the same type.
145
145
if ( anyOf . Count == 0 )
146
146
{
147
147
schemaType = derivedSchema . Type ;
@@ -245,6 +245,9 @@ private static JsonSchema MapJsonSchemaCore(
245
245
246
246
( properties ??= [ ] ) . Add ( new ( property . Name , propertySchema ) ) ;
247
247
248
+ // Mark as required if either the property is required or the associated constructor parameter is non-optional.
249
+ // While the latter implies the former in cases where the JsonSerializerOptions.RespectRequiredConstructorParameters
250
+ // setting has been enabled, for the case of the schema exporter we always mark non-optional constructor parameters as required.
248
251
if ( property is { IsRequired : true } or { AssociatedParameter . IsRequiredParameter : true } )
249
252
{
250
253
( required ??= [ ] ) . Add ( property . Name ) ;
@@ -340,13 +343,17 @@ private static JsonSchema MapJsonSchemaCore(
340
343
341
344
default :
342
345
Debug . Assert ( typeInfo . Kind is JsonTypeInfoKind . None ) ;
346
+ // Return a `true` schema for types with user-defined converters.
343
347
return CompleteSchema ( ref state , JsonSchema . True ) ;
344
348
}
345
349
346
350
JsonSchema CompleteSchema ( ref GenerationState state , JsonSchema schema )
347
351
{
348
352
if ( schema . Ref is null )
349
353
{
354
+ // A schema is marked as nullable if either
355
+ // 1. We have a schema for a property where either the getter or setter are marked as nullable.
356
+ // 2. We have a schema for a reference type, unless we're explicitly treating null-oblivious types as non-nullable.
350
357
bool isNullableSchema = propertyInfo != null
351
358
? propertyInfo . IsGetNullable || propertyInfo . IsSetNullable
352
359
: typeInfo . CanBeNull && ! parentPolymorphicTypeIsNonNullable && ! state . ExporterOptions . TreatNullObliviousAsNonNullable ;
@@ -364,6 +371,7 @@ JsonSchema CompleteSchema(ref GenerationState state, JsonSchema schema)
364
371
365
372
if ( state . ExporterOptions . TransformSchemaNode != null )
366
373
{
374
+ // Prime the schema for invocation by the JsonNode transformer.
367
375
schema . ExporterContext = state . CreateContext ( typeInfo , propertyInfo ) ;
368
376
}
369
377
0 commit comments