OpenAPITools / openapi-generator

OpenAPI Generator allows generation of API client libraries (SDK generation), server stubs, documentation and configuration automatically given an OpenAPI Spec (v2, v3)
https://openapi-generator.tech
Apache License 2.0
21.19k stars 6.42k forks source link

[BUG] [JAVA] openapi-generator-maven-plugin does not handle allOf composed of multiple objects #10010

Open norbjd opened 3 years ago

norbjd commented 3 years ago

Bug Report Checklist

Description

Using allOf composed of multiple objects in a response does not generate a class combining these multiple objects. Instead it uses the first class defined in the allOf section.

openapi-generator version

Version 5.2.0:

<plugin>
    <groupId>org.openapitools</groupId>
    <artifactId>openapi-generator-maven-plugin</artifactId>
    <version>5.2.0</version>
</plugin>

I have also tested with master (5.2.1-SNAPSHOT), commit fe9636e9.

OpenAPI declaration file content or url

Important part here is the allOf:

openapi: 3.0.0
info:
  title: Test
  version: v1
paths:
  /test:
    get:
      operationId: get
      responses:
        '200':
          description: Get
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/A'
                  - $ref: '#/components/schemas/B'
components:
  schemas:
    A:
      type: object
      properties:
        attA:
          type: string
    B:
      type: object
      properties:
        attB:
          type: integer
Generation Details
generatorName: java
inputSpec: openapi.yaml
Steps to reproduce
 mvn org.openapitools:openapi-generator-maven-plugin:5.2.0:generate \
    -Dopenapi.generator.maven.plugin.inputSpec=openapi.yaml \
    -Dopenapi.generator.maven.plugin.generatorName=java

Shows a warning:

[WARNING] allOf with multiple schemas defined. Using only the first one: A

It generates classes A and B. But when calling get(), the value returned by the call is A:

DefaultApi api = new DefaultApi();
A a = api.get();

I expected instead a composite object with A and B properties (attA and attB), like this (result from https://editor.swagger.io/):

image

Related issues/PRs
Suggest a fix
duracotton commented 1 year ago

@norbjd: Actually your example does not generate the same results anymore if you have an additional hierarchy like this:

schema:
  allOf:
    - $ref: '#/components/schemas/A'
  properties:
    b:
      type: object
      properties:
           blub:
                type: string

vs

schema:
  allOf:
    - $ref: '#/components/schemas/A'
    - type: object
      properties:
        b:
           type: object
           properties:
               blub:
                   type: string
yu-iskw commented 1 year ago

I have the same issue with a swagger.json generated by https://github.com/lukeautry/tsoa . Any updates?

justinfx commented 1 year ago

I have a similar issue using the following spec, with the Go language target:

openapi: 3.0.3
info:
  title: ''
  version: ''
paths:
  /path/request:
    post:
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                items:
                  type: array
                  items:
                    allOf:
                      - $ref: '#/components/schemas/EntityLink'
                    properties:
                      __type:
                        enum:
                          - itemName
      responses: {}
components:
  schemas:
    EntityType:
      type: string
    EntityLink:
      type: object
      properties:
        __type:
          $ref: '#/components/schemas/EntityType'
      required:
        - __type

The resulting problem is that "type" -> Type field ends up defined as a string pointer (optional) when it is supposed to be a value, because of the `required: ["type"]`, so we get broken code like this:

type PathRequestPostRequestItemsInner struct {
    Type *string `json:"__type,omitempty"`
}
func NewPathRequestPostRequestItemsInner(type_ string) *PathRequestPostRequestItemsInner {
    this := PathRequestPostRequestItemsInner{}
    this.Type = type_    // <--- Note, this is trying to assign string to *string
    return &this
}

The manual fix is to transform the spec to inject a required at the same level as the allOf/properties:

                  items:
                    allOf:
                      - $ref: '#/components/schemas/EntityLink'
                    properties:
                      __type:
                        enum:
                          - itemName
                    required:
                      - __type
isadounikau commented 11 months ago

Hello @wing328 I didn't find corresponding issue for Kotlin generator, however the issue persist. Therefore I added a small draft pr example of the possible solution. https://github.com/OpenAPITools/openapi-generator/pull/16573 I assume it could work for Java classes as well

wing328 commented 11 months ago

@isadounikau did you use the openapi-normalizer with the rule REFACTOR_ALLOF_WITH_PROPERTIES_ONLY enabled? e.g.

java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar generate -g java -i https://developers.pipedrive.com/docs/api/v1/openapi.yaml -o /tmp/allofbugfix3/ --openapi-normalizer REFACTOR_ALLOF_WITH_PROPERTIES_ONLY=true,SIMPLIFY_BOOLEAN_ENUM=true
dnlgrgly commented 4 months ago

I'm still experiencing the same issue with typescript-axios, even with REFACTOR_ALLOF_WITH_PROPERTIES_ONLY enabled.

jan-mawh commented 1 month ago

I also have issues with allOf not working. I know there is this workaround with openapi-normalizer with the rule REFACTOR_ALLOF_WITH_PROPERTIES_ONLY, but as far as i understand it does only work with a specification that isn't truly compatible with OpenApi 3.x - this is a great drawback because we want to provide a fully compatible specification to our customers... Any plans to address this issue soon?