44using System ;
55using System . Collections . Generic ;
66using System . Linq ;
7+ using System . Text . Json ;
78using System . Text . Json . Nodes ;
9+ using Microsoft . OpenApi . Any ;
810using Microsoft . OpenApi . Extensions ;
911using Microsoft . OpenApi . Helpers ;
1012using Microsoft . OpenApi . Interfaces ;
@@ -356,12 +358,6 @@ private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version
356358 // default
357359 writer . WriteOptionalObject ( OpenApiConstants . Default , Default , ( w , d ) => w . WriteAny ( d ) ) ;
358360
359- // nullable
360- if ( version is OpenApiSpecVersion . OpenApi3_0 )
361- {
362- writer . WriteProperty ( OpenApiConstants . Nullable , Nullable , false ) ;
363- }
364-
365361 // discriminator
366362 writer . WriteOptionalObject ( OpenApiConstants . Discriminator , Discriminator , callback ) ;
367363
@@ -636,20 +632,39 @@ private void SerializeAsV2(
636632
637633 private void SerializeTypeProperty ( JsonSchemaType ? type , IOpenApiWriter writer , OpenApiSpecVersion version )
638634 {
635+ // check whether nullable is true for upcasting purposes
636+ var isNullable = Nullable ||
637+ ( Type . HasValue && Type . Value . HasFlag ( JsonSchemaType . Null ) ) ||
638+ Extensions is not null &&
639+ Extensions . TryGetValue ( OpenApiConstants . NullableExtension , out var nullExtRawValue ) &&
640+ nullExtRawValue is OpenApiAny { Node : JsonNode jsonNode } &&
641+ jsonNode . GetValueKind ( ) is JsonValueKind . True ;
639642 if ( type is null )
640643 {
641- return ;
642- }
643- if ( ! HasMultipleTypes ( type . Value ) )
644- {
645- // check whether nullable is true for upcasting purposes
646- if ( version is OpenApiSpecVersion . OpenApi3_1 && ( Nullable || Extensions . ContainsKey ( OpenApiConstants . NullableExtension ) ) )
644+ if ( version is OpenApiSpecVersion . OpenApi3_0 && isNullable )
647645 {
648- UpCastSchemaTypeToV31 ( type , writer ) ;
646+ writer . WriteProperty ( OpenApiConstants . Nullable , true ) ;
649647 }
650- else
648+ }
649+ else if ( ! HasMultipleTypes ( type . Value ) )
650+ {
651+
652+ switch ( version )
651653 {
652- writer . WriteProperty ( OpenApiConstants . Type , type . Value . ToIdentifier ( ) ) ;
654+ case OpenApiSpecVersion . OpenApi3_1 when isNullable :
655+ UpCastSchemaTypeToV31 ( type . Value , writer ) ;
656+ break ;
657+ case OpenApiSpecVersion . OpenApi3_0 when isNullable && type . Value == JsonSchemaType . Null :
658+ writer . WriteProperty ( OpenApiConstants . Nullable , true ) ;
659+ writer . WriteProperty ( OpenApiConstants . Type , JsonSchemaType . Object . ToIdentifier ( ) ) ;
660+ break ;
661+ case OpenApiSpecVersion . OpenApi3_0 when isNullable && type . Value != JsonSchemaType . Null :
662+ writer . WriteProperty ( OpenApiConstants . Nullable , true ) ;
663+ writer . WriteProperty ( OpenApiConstants . Type , type . Value . ToIdentifier ( ) ) ;
664+ break ;
665+ default :
666+ writer . WriteProperty ( OpenApiConstants . Type , type . Value . ToIdentifier ( ) ) ;
667+ break ;
653668 }
654669 }
655670 else
@@ -664,6 +679,10 @@ private void SerializeTypeProperty(JsonSchemaType? type, IOpenApiWriter writer,
664679 var list = ( from JsonSchemaType flag in jsonSchemaTypeValues
665680 where type . Value . HasFlag ( flag )
666681 select flag ) . ToList ( ) ;
682+ if ( Nullable && ! list . Contains ( JsonSchemaType . Null ) )
683+ {
684+ list . Add ( JsonSchemaType . Null ) ;
685+ }
667686 writer . WriteOptionalCollection ( OpenApiConstants . Type , list , ( w , s ) => w . WriteValue ( s . ToIdentifier ( ) ) ) ;
668687 }
669688 }
@@ -681,14 +700,21 @@ private static bool HasMultipleTypes(JsonSchemaType schemaType)
681700 schemaTypeNumeric != ( int ) JsonSchemaType . Null ;
682701 }
683702
684- private void UpCastSchemaTypeToV31 ( JsonSchemaType ? type , IOpenApiWriter writer )
703+ private static void UpCastSchemaTypeToV31 ( JsonSchemaType type , IOpenApiWriter writer )
685704 {
686705 // create a new array and insert the type and "null" as values
687- Type = type | JsonSchemaType . Null ;
688- var list = ( from JsonSchemaType ? flag in jsonSchemaTypeValues // Check if the flag is set in 'type' using a bitwise AND operation
689- where Type . Value . HasFlag ( flag )
706+ var temporaryType = type | JsonSchemaType . Null ;
707+ var list = ( from JsonSchemaType flag in jsonSchemaTypeValues // Check if the flag is set in 'type' using a bitwise AND operation
708+ where temporaryType . HasFlag ( flag )
690709 select flag . ToIdentifier ( ) ) . ToList ( ) ;
691- writer . WriteOptionalCollection ( OpenApiConstants . Type , list , ( w , s ) => w . WriteValue ( s ) ) ;
710+ if ( list . Count > 1 )
711+ {
712+ writer . WriteOptionalCollection ( OpenApiConstants . Type , list , ( w , s ) => w . WriteValue ( s ) ) ;
713+ }
714+ else
715+ {
716+ writer . WriteProperty ( OpenApiConstants . Type , list [ 0 ] ) ;
717+ }
692718 }
693719
694720#if NET5_0_OR_GREATER
@@ -711,7 +737,7 @@ private void DowncastTypeArrayToV2OrV3(JsonSchemaType schemaType, IOpenApiWriter
711737
712738 if ( ! HasMultipleTypes ( schemaType ^ JsonSchemaType . Null ) && ( schemaType & JsonSchemaType . Null ) == JsonSchemaType . Null ) // checks for two values and one is null
713739 {
714- foreach ( JsonSchemaType ? flag in jsonSchemaTypeValues )
740+ foreach ( JsonSchemaType flag in jsonSchemaTypeValues )
715741 {
716742 // Skip if the flag is not set or if it's the Null flag
717743 if ( schemaType . HasFlag ( flag ) && flag != JsonSchemaType . Null )
0 commit comments