diff --git a/docs/apispec-docs/src/main/scala/sttp/tapir/docs/apispec/schema/TSchemaToASchema.scala b/docs/apispec-docs/src/main/scala/sttp/tapir/docs/apispec/schema/TSchemaToASchema.scala index f32985ad58..1ba9b47474 100644 --- a/docs/apispec-docs/src/main/scala/sttp/tapir/docs/apispec/schema/TSchemaToASchema.scala +++ b/docs/apispec-docs/src/main/scala/sttp/tapir/docs/apispec/schema/TSchemaToASchema.scala @@ -26,8 +26,12 @@ private[schema] class TSchemaToASchema(toSchemaReference: ToSchemaReference, mar case TSchemaType.SArray(nested @ TSchema(_, Some(name), _, _, _, _, _, _, _, _, _)) => ASchema(SchemaType.Array).copy(items = Some(toSchemaReference.map(nested, name))) case TSchemaType.SArray(el) => ASchema(SchemaType.Array).copy(items = Some(apply(el))) - case TSchemaType.SOption(nested @ TSchema(_, Some(name), _, _, _, _, _, _, _, _, _)) if !markOptionsAsNullable => - toSchemaReference.map(nested, name) + case TSchemaType.SOption(nested @ TSchema(_, Some(name), _, _, _, _, _, _, _, _, _)) => { + val ref = toSchemaReference.map(nested, name) + if (!markOptionsAsNullable) ref + else + ASchema.oneOf(List(ref), ref.discriminator).copy(nullable = Some(true)) + } case TSchemaType.SOption(el) => apply(el, isOptionElement = true) case TSchemaType.SBinary() => ASchema(SchemaType.String).copy(format = SchemaFormat.Binary) case TSchemaType.SDate() => ASchema(SchemaType.String).copy(format = SchemaFormat.Date) diff --git a/docs/openapi-docs/src/test/resources/expected_nullable_option_class_field.yml b/docs/openapi-docs/src/test/resources/expected_nullable_option_class_field.yml index f6ad2f2a3a..05bf273af0 100644 --- a/docs/openapi-docs/src/test/resources/expected_nullable_option_class_field.yml +++ b/docs/openapi-docs/src/test/resources/expected_nullable_option_class_field.yml @@ -40,15 +40,9 @@ components: - requiredStringField type: object properties: - optionalObjField: - required: - - bar - type: - - object - - 'null' - properties: - bar: - type: integer - format: int32 + optionalClassField: + oneOf: + - $ref: '#/components/schemas/Bar' + - type: 'null' requiredStringField: type: string diff --git a/docs/openapi-docs/src/test/scalajvm/sttp/tapir/docs/openapi/VerifyYamlTest.scala b/docs/openapi-docs/src/test/scalajvm/sttp/tapir/docs/openapi/VerifyYamlTest.scala index 88745adec5..8a5553ddae 100644 --- a/docs/openapi-docs/src/test/scalajvm/sttp/tapir/docs/openapi/VerifyYamlTest.scala +++ b/docs/openapi-docs/src/test/scalajvm/sttp/tapir/docs/openapi/VerifyYamlTest.scala @@ -666,7 +666,7 @@ class VerifyYamlTest extends AnyFunSuite with Matchers { actualYamlNoIndent shouldBe expectedYaml } - test("should mark optional class fields as nullable by inlining them when configured to do so") { + test("should mark optional class fields as nullable when configured to do so") { case class Bar(bar: Int) case class ClassWithOptionClassField(optionalObjField: Option[Bar], requiredStringField: String)