OpenAPITools / OpenAPITools/openapi-generator

[BUG][Java][okhttp-gson] oneOf support is failing by not setting and validate discriminator type

Open
#14,309 6 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Issue: Bug
Dominant language
Java
Stars
26.8k
Forks
7.7k
PR merge metrics
PR metrics pending

Description

Bug Report Checklist
  • Have you provided a full/minimal spec to reproduce the issue?
  • Have you validated the input using an OpenAPI validator (example)?
  • Have you tested with the latest master to confirm the issue still exists?
  • Have you searched for related issues/PRs?
  • What's the actual output vs expected output?
  • [Optional] Sponsorship to speed up the bug fix or feature request (example)
Description
  1. Okhttp-gson client fails by not sending the discriminator type during communication with a backend.
  • Expected result:
    Client sends discriminator type correctly, and server can deserialize correctly.

  • Actual result:

Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error:
     Could not resolve subtype of [simple type, class server.api.PhysicalMountingApiModel]: missing type id property 'object_type' (for POJO property 'mounting')]
  1. Sending List with multiple oneOf from server (server sends the discriminator "object_type" correctly) - the client fails during property validation phase.
  • Expected result:
    Client can deserialize server payload into correct objects based on discriminator.

  • Actual result:

     2 class(es) match the result, expected 1.
     Detailed failure message for oneOf schemas: [Deserialization for FloorMounting failed with`The required field `orientation` is not found in the JSON string: {"object_type":"LocationMounting","mountable_type":"FIXED"}`.].
     JSON: {"object_type":"LocationMounting","mountable_type":"FIXED"}

useOneOfDiscriminatorLookup has been enabled for okhttp-gson client.

openapi-generator version

6.2.1

OpenAPI declaration file content
openapi: 3.0.3
info:
  contact:
    email: email@email.com
    name: name
    url: https://whatever.com
  description: Internal API
  title: Internal API
  version: 1.0.0
  x-audience: business-unit-internal
  x-api-id: 3addb128-c3fb-4bfe-a5d9-c84b3bd58ca2
servers:
- description: Local environment
  url: http://localhost:9090/api
paths:
  /authenticated/organizations/aspects/physical-aspects/:
    get:
      operationId: listAll
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PhysicalAspectsResponse'
          description: List of the physicals
      summary: List all physicals
      tags:
      - Physical
      x-accepts: application/json
    put:
      operationId: update
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdatePhysicalRequest'
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PhysicalAspectResponse'
          description: Physical aspect updated successfully
      summary: Update Physical aspect
      tags:
      - Physical
      x-content-type: application/json
      x-accepts: application/json
components:
  schemas:
    PhysicalAspectsResponse:
      example:
        physicals:
        - identifiable_id: 046b6c7f-0b8a-43b9-b35d-6489e6daee91
          mounting: null
        - identifiable_id: 046b6c7f-0b8a-43b9-b35d-6489e6daee91
          mounting: null
      properties:
        physicals:
          items:
            $ref: '#/components/schemas/PhysicalAspect'
          type: array
      required:
      - physicals
      type: object
    UpdatePhysicalRequest:
      example:
        physical:
          identifiable_id: 046b6c7f-0b8a-43b9-b35d-6489e6daee91
          mounting: null
      properties:
        physical:
          $ref: '#/components/schemas/PhysicalAspect'
      required:
      - physical
      type: object
    PhysicalAspectResponse:
      example:
        physical:
          identifiable_id: 046b6c7f-0b8a-43b9-b35d-6489e6daee91
          mounting: null
      properties:
        physical:
          $ref: '#/components/schemas/PhysicalAspect'
      required:
      - physical
      type: object
    PhysicalAspect:
      example:
        identifiable_id: 046b6c7f-0b8a-43b9-b35d-6489e6daee91
        mounting: null
      properties:
        identifiable_id:
          format: uuid
          type: string
        mounting:
          $ref: '#/components/schemas/PhysicalMounting'
      required:
      - definition
      - identifiable_id
      - mountable
      - mounting
      type: object
    PhysicalMounting:
      discriminator:
        propertyName: object_type
      oneOf:
      - $ref: '#/components/schemas/NotMountedMounting'
      - $ref: '#/components/schemas/FloorMounting'
      - $ref: '#/components/schemas/LocationMounting'
      type: object
    NotMountedMounting:
      properties:
        object_type:
          type: string
        mountable_type:
          $ref: '#/components/schemas/MountableType'
      required:
      - object_type
      type: object
    FloorMounting:
      properties:
        object_type:
          type: string
        mountable_type:
          $ref: '#/components/schemas/MountableType'
        orientation:
          format: float
          maximum: 360
          minimum: -360
          type: number
      required:
      - object_type
      - orientation
      type: object
    LocationMounting:
      properties:
        object_type:
          type: string
        mountable_type:
          $ref: '#/components/schemas/MountableType'
      required:
      - object_type
      type: object
    MountableType:
      enum:
      - FIXED
      - LOCATION
      type: string
Steps to reproduce

I've included a reproducible test project based on a Maven project, Spring Boot 2.7.x and Java 17 using okhttp, jersey2 and spring-cloud libraries for comparison.
okhttp-gson-jersey2-springcloud-testcase.zip

Testcases are placed in Jersey2Test.java, OkHttpTest.java and SpringCloudTest.java

Download the testcase and mvn clean install. Testcases can be found in #DemoApplicationTests

cc @bbdouglas (2017/07) @sreeshas (2017/08) @jfiala (2017/08) @lukoyanov (2017/09) @cbornet (2017/09) @jeff9finger (2018/01) @karismann (2019/03) @Zomzog (2019/04) @lwlee2608 (2019/10)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Download the linked Maven testcase and run mvn clean install; begin with OkHttpTest.java and the cases in DemoApplicationTests, comparing them with Jersey2Test.java and SpringCloudTest.java. Trace the okhttp-gson handling of the oneOf discriminator. Done means requests send object_type and responses deserialize each payload into the correct subtype without validation ambiguity.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
api, backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.