'How to use OpenAPI "oneOf" property with openapi-generator-maven-plugin when generating Spring code

I am developing an application with an Angular frontend and RESTful Spring Boot Backend

I found this very handy maven plugin openapi-generator-maven-plugin from org.openapitools. With its code generation capability, it helps enforce a "contract first" approach between the frontend and backend for our API. But our swagger file uses "oneOf" property in the requestBody and responseBody definitions. I've tried to generate Spring code from this, but the generated Java class has missing imports:

import com.pack.api.dto.OneOfLatteCoffeAmericanoCoffe;
import com.pack.api.dto.UNKNOWN_BASE_TYPE;

Is there away to cofigue the plugin to work with Swagger's oneOf property? I'm usig Spring Boot 2.3.1, Swagger 3.0 and Openapi-generator-maven-plugin 4.3



Solution 1:[1]

Currently, openapi-generator doesn't support oneOf. This is a capability that had been newly introduced with OpenAPI v3 (FYI, only v2 and below are called "Swagger", it has then been renamed to OpenAPI). There are various generators (Java, Spring, lots of other languages). I have seen that contributions have been made during this year to enable oneOf support.

To sum up, it looks like you have to wait a bit more until you can exploit this feature of the OpenAPI v3 spec using the generator for Spring.

Edit: It's also listed on the "short term roadmap":

OAS3.0 features support: anyOf, oneOf, callbacks, etc

Solution 2:[2]

If you can modify your swagger, you may replace the oneOf with a reference to an abstract type.

For example, if your swagger looks like this :

components:
  schemas:
    'Parent':
      'vehicle':
        oneOf:
        - type: object
          properties:
            'car_property':
              type: string
        - type: object
          properties:
            'truck_property':
              type: string

You can modify it like that :

components:
  schemas:
    'Parent':
      type: object
      properties:
        'vehicle':
          $ref: '#/components/schemas/Vehicle'
    #---------------------------------------------------------------------------
    # Abstract class with discriminator 'vehicle_type'
    #---------------------------------------------------------------------------
    'Vehicle':
      type: object
      properties:
        'vehicle_type':
          type: string
          enum: [ 'CAR', 'TRUCK' ]
      discriminator:
        propertyName: vehicle_type
        mapping:
          'CAR': '#/components/schemas/Car'
          'TRUCK': '#/components/schemas/Truck'
    #---------------------------------------------------------------------------
    # Concrete classes
    #---------------------------------------------------------------------------
    'Car':
      allOf:
      - $ref: "#/components/schemas/Vehicle"
      - type: object
        properties:
          'car_property':
            type: string
    'Truck':
      allOf:
      - $ref: "#/components/schemas/Vehicle"
      - type: object
        properties:
          'truck_property':
            type: string

This swagger modification makes the generator work. It handles the same JSON objects though I am not 100% sure it is semanticaly equivalent in OpenAPI specification.

Solution 3:[3]

We've added better oneOf and anyOf support to some generators such as java (jersey2), csharp-netcore and more. Please give it a try with the latest master. SNAPSHOT versions can be found in the project's README: https://github.com/OpenAPITools/openapi-generator/

Solution 4:[4]

For me csharp generated model object that is created is not correct. It generates following,

[DataMember(Name = "category", IsRequired = true, EmitDefaultValue = true)]
public OneOfobjectobjectobject Category { get; set; }

It creates an object starting with word Oneof and append three object since I have three oneOfs in my openapi spec doc for Category. Is there a way to return a dictionary or something? The above code doesn't compile. my openapi schema for category is as following

category:
          title: Category
          oneOf:
            - title: Year
              type: object
              properties:
                type:
                  title: Type
                  enum:
                    - year
                  type: string
              additionalProperties: false
              required:
                - type
            - title: Term
              type: object
              properties:
                type:
                  title: Type
                  enum:
                    - term
                  type: string
                parent:
                  title: Parent
                  oneOf:
                    - title: Academic Period
                      type: object
                      properties:
                        academicPeriod:
                          title: Academic Period
                          type: object
                          properties:
                            id:
                              title: ID
                              description: The global identifier for the Academic Period.
                              type: string
                              format: guid
                              pattern: ^[a-f0-9]{8}(?:-[a-f0-9]{4}){3}-[a-f0-9]{12}$
                          additionalProperties: false
                          required:
                            - id
                      additionalProperties: false
                      required:
                        - academicPeriod
                    - title: Academic Year
                      type: object
                      properties:
                        academicYear:
                          title: Academic Year
                          type: number
                      additionalProperties: false
                      required:
                        - academicYear
                preceding:
                  title: Preceding
                  oneOf:
                    - type: object
                      properties:
                        id:
                          title: ID
                          description: The global identifier for the Preceding.
                          type: string
                          format: guid
                          pattern: ^[a-f0-9]{8}(?:-[a-f0-9]{4}){3}-[a-f0-9]{12}$
                      additionalProperties: false
                      required:
                        - id
                    - type: object
                      maxProperties: 0
              additionalProperties: false
              required:
                - type
            - title: Subterm
              type: object
              properties:
                type:
                  title: Type
                  enum:
                    - subterm
                  type: string
                parent:
                  title: Parent
                  type: object
                  properties:
                    id:
                      title: ID
                      description: The global identifier for the Parent.
                      type: string
                      format: guid
                      pattern: ^[a-f0-9]{8}(?:-[a-f0-9]{4}){3}-[a-f0-9]{12}$
                  additionalProperties: false
                  required:
                    - id
                preceding:
                  title: Preceding
                  oneOf:
                    - type: object
                      properties:
                        id:
                          title: ID
                          description: The global identifier for the Preceding.
                          type: string
                          format: guid
                          pattern: ^[a-f0-9]{8}(?:-[a-f0-9]{4}){3}-[a-f0-9]{12}$
                      additionalProperties: false
                      required:
                        - id
                    - type: object
                      maxProperties: 0
                sectionDateOverride:
                  title: Section Date Override
                  oneOf:
                    - type: string
                      enum:
                        - notAllowed
                    - type: string
                      maxLength: 0
              additionalProperties: false
              required:
                - type
                - parent

Solution 5:[5]

I using @openapitools/openapi-generator-cli and i tried this java snapshot https://oss.sonatype.org/content/repositories/snapshots/org/openapitools/openapi-generator-cli/6.0.0-SNAPSHOT/openapi-generator-cli-${versionName}.jar and it worked for me.

Just need setup openapitools.json like this -

{
  "$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json",
  "spaces": 2,
  "generator-cli": {
    "version": "6.0.0-20211025.061654-22",
    "repository": {
      "downloadUrl": "https://oss.sonatype.org/content/repositories/snapshots/org/openapitools/openapi-generator-cli/6.0.0-SNAPSHOT/openapi-generator-cli-${versionName}.jar"
    }
  }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Ivan Ponomarev
Solution 3 William Cheng
Solution 4
Solution 5 Vít Zadina