Skip to content

Conversation

@wing328
Copy link
Member

@wing328 wing328 commented Nov 17, 2025

update normalizer to handle siblings of schema with $ref by converting it to allOf, e.g. normalize

        refProperty:
          description: Ref-Property-Description
          $ref: '#/components/schemas/RefObject'

to

        refProperty:
          description: Ref-Property-Description
          allOf:
            - $ref: '#/components/schemas/RefObject'

Close #20304

PR checklist

  • Read the contribution guidelines.
  • Pull Request title clearly describes the work in the pull request and Pull Request description provides details about how to validate the work. Missing information here may result in delayed response from the community.
  • Run the following to build the project and update samples:
    ./mvnw clean package || exit
    ./bin/generate-samples.sh ./bin/configs/*.yaml || exit
    ./bin/utils/export_docs_generators.sh || exit
    
    (For Windows users, please run the script in WSL)
    Commit all changed files.
    This is important, as CI jobs will verify all generator outputs of your HEAD commit as it would merge with master.
    These must match the expectations made by your contribution.
    You may regenerate an individual generator by passing the relevant config(s) as an argument to the script, for example ./bin/generate-samples.sh bin/configs/java*.
    IMPORTANT: Do NOT purge/delete any folders/files (e.g. tests) when regenerating the samples as manually written tests may be removed.
  • File the PR against the correct branch: master (upcoming 7.x.0 minor release - breaking changes with fallbacks), 8.0.x (breaking changes without fallbacks)
  • If your PR solves a reported issue, reference it using GitHub's linking syntax (e.g., having "fixes #123" present in the PR description)
  • If your PR is targeting a particular programming language, @mention the technical committee members, so they are more likely to review the pull request.

@wing328 wing328 added Feature: OAS 3.1.0 spec support OpenAPI Normalizer Normalize the spec for easier processing labels Nov 17, 2025
@wing328 wing328 added this to the 7.18.0 milestone Nov 17, 2025
@wing328 wing328 mentioned this pull request Nov 17, 2025
6 tasks
@wing328 wing328 marked this pull request as ready for review November 17, 2025 10:30
@wing328 wing328 changed the title Fix $ref sibling using allOf in openapi normalizer Fix siblings of $ref using allOf in openapi normalizer Nov 17, 2025
@wing328 wing328 merged commit 554e10d into master Nov 19, 2025
169 checks passed
@jpfinne
Copy link
Contributor

jpfinne commented Nov 22, 2025

@wing328 You've tested with simple types (type: string). I think you introduce breaking changes for complex types.

Example:

components:
  schemas:
    Base:
      description: Base Description
      type: object
      properties:
        id:
          type: integer
    BaseWithDescription:
      description: Base With Description
      $ref: '#/components/schemas/Base'

    Parent:
      description: Parent description
      type: object
      x-parent: true
      properties:
        id:
          type: integer
    Child:
      description: Child With Description
      $ref: '#/components/schemas/Parent'

I've tested with the spring generator.
In 7.4.0, 2 classes were generated: Base.java and Parent.java
After this PR, 4 classes are generated: Base.java, Parent.java, BaseWithDescription.java and Child.java (class Child extends Parent)

ModelUtils.isComplexComposedSchema(Schema) could be used to discard the complex types (eventually configurable).

I have a question about the use of allOf.
For simple type, you could inline the sibling type. Isn't it simpler for the generators?

RefObject:
   type: string
refProperty:
   description: Ref-Property-Description
   $ref: '#/components/schemas/RefObject'

becomes:

RefObject:
   type: string
refProperty:
   description: Ref-Property-Description
   type: string

@wing328 wing328 deleted the normalize-ref-siblings branch November 24, 2025 11:17
@wing328
Copy link
Member Author

wing328 commented Nov 24, 2025

In 7.4.0, 2 classes were generated: Base.java and Parent.java

7.4.0 was released a while ago. Are you able to reproduce the issue with v7.17.0? just want to confirm the issue is with this change not earlier stable version v7.17.0

and thanks for testing it. i'll take another look.

@jpfinne
Copy link
Contributor

jpfinne commented Nov 24, 2025

Sorry, It is indeed a regression from 7.16.0.

@wing328
Copy link
Member Author

wing328 commented Nov 24, 2025

about use of allOf, please refer to https://stackoverflow.com/a/51402417/677735 for more info.

We support the openapi 3.0.x way of overriding fields and that's why openapi normalizer normalizes schemas (e.g. 3.1) to conform to this way so that default codegen can handle these schemas with ease.

@wing328
Copy link
Member Author

wing328 commented Nov 24, 2025

Sorry, It is indeed a regression from 7.16.0.

No need to sorry and thanks for testing it.

@jpfinne
Copy link
Contributor

jpfinne commented Nov 24, 2025

@wing328 the stackoverflow article descibes a nice way to patch an openapi 3,0 contract so that it has features only available in 3.1. The swagger parser does not keep attributes like description when there is a $ref in 3.0.

In this PR you do the opposite. You convert an openapi 3.1 contract to a 3.0 contract while keeping the functionality.

It would be nice if the code generation supports the pattern

    refProperty:
      description: Ref-Property-Description
      allOf:
        - $ref: '#/components/schemas/RefObject'

But unfortunately it does not !

I've tested this PR with the spring generator:

openapi: '3.1.0'
components:
  schemas:
    RefObject:
      type: string
    refProperty:
      description: Ref-Property-Description
      $ref: '#/components/schemas/RefObject'
    Base:
      type: object
      properties:
        refProperty:
          $ref: '#/components/schemas/refProperty'

It generates an Object instead of a String in pre-PR.

public class Base {

  private @Nullable Object refProperty;

In the normalizer, there is already a parsed OpenAPI. So the trick is not really needed.
Inlining is an option for simple types.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Feature: OAS 3.1.0 spec support OpenAPI Normalizer Normalize the spec for easier processing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] [OpenAPI 3.1] siblings of $ref are lost

3 participants