Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OpenAPI 3.0.3 Schema Incorrectly Includes enum: [null] When Description is Present in @Schema Annotation #2145

Closed
charlesjiang-greengate opened this issue Jan 13, 2025 · 3 comments · Fixed by #2152

Comments

@charlesjiang-greengate
Copy link

Description:

When generating OpenAPI 3.0.3 schema using SmallRye OpenAPI, if a field's @Schema annotation includes a description, the generator incorrectly adds enum: [null] to the schema for nullable fields. This doesn't occur when the description is omitted.

Example code:

Code:

@Schema(description = "This is a test record for demonstrating the bug")
public record HelloWorld(
        @Schema(description = "If the field has description, then null is included",
                required = true,
                nullable = true)
        Subject incorrectOutput,
        @Schema(
                // no description, correct output
                required = true,
                nullable = true)
        Subject correctOutput) {}

Configuration: application.properties force OpenAPI to 3.0.3

mp.openapi.extensions.smallrye.openapi=3.0.3

Resulting Schema

    HelloWorld:
      description: This is a test record for demonstrating the bug
      required:
      - incorrectOutput
      - correctOutput
      type: object
      properties:
        incorrectOutput:
          description: "If the field has description, then null is included"
          type: string
          anyOf:
          - $ref: "#/components/schemas/Subject"
          - enum:
            - null
          nullable: true
        correctOutput:
          allOf:
          - $ref: "#/components/schemas/Subject"
          nullable: true

Issue:

  • The incorrectOutput field (with description) incorrectly includes enum: [null]
  • The correctOutput field (without description) generates the correct schema
  • Both fields are configured identically except for the presence of a description

I'm using quarkus 3.17.5, which includes io.smallrye:smallrye-open-api-core:4.0.5.

Thank you for your help!

@Azquelt
Copy link
Contributor

Azquelt commented Jan 13, 2025

Hmm, some interesting things going on here.

  • Your incorrectOutput also has type: string, which is presumably wrong?
  • The enum: [null] doesn't actually affect which objects are valid, since it's within an anyOf array and the parent schema has nullable = true.

Internally, we use the OpenAPI 3.1 model right up until we serialize. The code that does the transformation of 3.1 -> 3.0 schema is in SchemaIO so likely something is wrong here.

In general this pattern is annoying to translate.

In OpenAPI 3.0 you could do this:

mySchema:
  allOf:
  - $ref: "#/components/schemas/aSchema"
  nullable: true

Whereas in OpenAPI 3.1, nullable does not exist, so we generate this:

mySchema:
  anyOf:
  - $ref: "#/components/schemas/aSchema"
  - type: "null"

I will have a look to see what's going wrong here.

@charlesjiang-greengate
Copy link
Author

@Azquelt , Thank you for looking into it.

Sorry for the confusion, type:string is due to

    Subject:
      enum:
      - ALICE
      - BOB
      type: string

Please let me know if you would like me to attach a reproducer project for this issue.

Thank you!

@Azquelt
Copy link
Contributor

Azquelt commented Jan 14, 2025

Ok, I think I see why this happens any why having a description makes a difference.

AnnotationTargetProcessor.processField() will replace the whole schema for the field with a reference to the type of the field if the field has no additional "assertion" or "annotation" properties (description in JSON schema terms is an "annotation" because it adds information about the object without asserting anything).

In this case we end up with something like:

$ref: "#/components/schema/MyType"

However, if there are additional properties on the field, it will add a reference to the schema for the field, drop any properties that match and add a type observer, which synchronises the type of the field with the type of the referenced schema.

In that case, we end up with something like:

$ref: "#/components/schema/MyType"
type: ["object", "null"]
description: My field description

Then, if the field is nullable but the referenced schema isn't, we turn that into this:

type: ["object", "null"]
anyOf:
  - $ref: "#/components/schema/MyType"
  - type: "null"
description: My field description

Finally, when we serialize, we convert this OpenAPI 3.1 model into OpenAPI 3.0 format and we have this check for turning an anyOf[{$ref}, {type=null}] into allOf[{$ref}], nullable=true. The last part of the check is result.type = null and that will only be true in the first case above where we replace the whole schema with a $ref.

I think we can remove that last part of the check. I just need to add some tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants