OpenAPITools / OpenAPITools/openapi-generator

[BUG][JAVA] Problem with request serialization / deserialization in case of oneOf caused by PR #20939

Open
#22,896 16 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

This problem is related to change in https://github.com/OpenAPITools/openapi-generator/pull/20939 related to bug report https://github.com/OpenAPITools/openapi-generator/issues/20938.

So it worked in version 7.14 and it is not working since actual 7.19.

I agree that correct behavior should be that only mapped discriminator should be included in generated interface for parent type, but it now breaks serialization / deserialization in client vs server communication.

Since parent interface contains these annotations it will override property of discriminator via Jackson mapper to simple class name but server now expect to receive explicit mapping that we have in yaml definition.

I will borrow example from original bug report with slight alternation:

    FruitRequest:
      discriminator:
        mapping:
          APPLE: '#/components/schemas/AppleRequest'
          BANANA: '#/components/schemas/BananaRequest'
        propertyName: fruitType
      oneOf:
      - $ref: '#/components/schemas/AppleRequest'
      - $ref: '#/components/schemas/BananaRequest'
      properties:
        fruitType:
          $ref: '#/components/schemas/FruitType'
      required:
      - fruitType
      type: object
      x-one-of-name: Fruit
    AppleRequest:
      properties:
        seeds:
          type: integer
      required:
      - seeds
      type: object
    BananaRequest:
      properties:
        length:
          type: integer
      required:
      - length
      type: object

then we will have:

@JsonIgnoreProperties(
    value = {"fruitType"},
    allowSetters = true
)
@JsonTypeInfo(
    use = Id.NAME,
    include = As.PROPERTY,
    property = "fruitType",
    visible = true
)
@JsonSubTypes({
  @JsonSubTypes.Type(value = Apple.class, name = "APPLE"),
  @JsonSubTypes.Type(value = Banana.class, name = "BANANA"),
  @JsonSubTypes.Type(value = Apple.class, name = "AppleRequest"),    // <-- not any more
  @JsonSubTypes.Type(value = Banana.class, name = "BananaRequest")   // <-- not any more
})

@Generated(value = "org.openapitools.codegen.languages.SpringCodegen", comments = "Generator version: 7.13.0-SNAPSHOT")
public interface Fruit {

Since fruitType is marked as ignored it will not be passed from client's DTO to the request and simpleClassName will be used which will not match on server side.
If we remove that JsonIgnoreProperties then both, the explicit discriminator property value and simpleClassName will be sent to server as fruitType and again, fail on deserialization.

Only think that worked for me was to also specify

@JsonTypeInfo(
use = Id.NAME,
include = As.EXISTING_PROPERTY,
property = "fruitType",
visible = true
)

that results in:

// no more @JsonIgnoreProperties
@JsonTypeInfo(
    use = Id.NAME,
    include = As.EXISTING_PROPERTY,
    property = "fruitType",
    visible = true
)
@JsonSubTypes({
  @JsonSubTypes.Type(value = Apple.class, name = "APPLE"),
  @JsonSubTypes.Type(value = Banana.class, name = "BANANA"),
})

@Generated(value = "org.openapitools.codegen.languages.SpringCodegen", comments = "Generator version: 7.13.0-SNAPSHOT")
public interface Fruit {

then its working correctly with only explicit discriminator mapping in parent interface.

There is also workaround for this issue, to define inside openapi.yml also mapping for simpleClassName

e.g.

    FruitRequest:
      discriminator:
        mapping:
          APPLE: '#/components/schemas/AppleRequest'
          BANANA: '#/components/schemas/BananaRequest'
          AppleRequest: '#/components/schemas/AppleRequest'
          BananaRequest: '#/components/schemas/BananaRequest'

I don't kwow if possible change in https://github.com/OpenAPITools/openapi-generator/blob/master/modules/openapi-generator/src/main/resources/JavaSpring/typeInfoAnnotation.mustache would break anything else, but at least some options to enable old behavior would be greatly appreciated :-)

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

Start with modules/openapi-generator/src/main/resources/JavaSpring/typeInfoAnnotation.mustache, then read PR #20939 and issue #20938 for the behavior change. Reproduce the FruitRequest oneOf case with the shown discriminator mapping and inspect generated Jackson annotations. Done means Java client/server serialization and deserialization preserve the explicit discriminator values without requiring duplicate simple-class-name mappings.

Written by the indexing model from the issue text.

Assessment

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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.