OpenAPITools / OpenAPITools/openapi-generator

[BUG] polymorphic discriminator deserialization inconsistent between Java/Dart

Open
#21,297 3 comments 1 reaction 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

Using the following specification, I was hoping that Store.pet might be deserialized as a Cat or Dog instance based upon the class name held in Store.pet.petType:

components:
  schemas:
    Store:
      type: object
      properties:
        pet:
          oneOf:
            - $ref: "#/components/schemas/Cat"
            - $ref: "#/components/schemas/Dog"
          discriminator:
            propertyName: petType
            mapping:
                Cat:  "#/components/schemas/Cat"
                Dog:  "#/components/schemas/Dog"
    Pet:
      discriminator:
        propertyName: petType
      required:
        - name
        - petType # required for inheritance to work
      properties:
        name:
          type: string
        petType:
          type: string
    Cat:
      allOf:
        - $ref: '#/components/schemas/Pet' # Cat has all properties of a Pet
        - properties: # extra properties only for cats
            huntingSkill:
              type: string
              default: lazy
              enum:
                - lazy
                - aggressive
    Dog:
      allOf:
        - $ref: '#/components/schemas/Pet' # Dog has all properties of a Pet
        - properties: # extra properties only for dogs
            packSize:
              description: The size of the pack the dog is from
              type: integer
openapi: 3.0.3
security: []
servers: []
paths: {}
info:
  version: 1.0.0
  title: Swagger Petstore

But when I generate the Dart client, there's a class StorePet that looks like the union of the properties of Cat and Dog... and no actual code in Store for deserializing a Cat or Dog into the attribute Store.pet based on pet.petType.

// java -jar openapi-generator-cli.jar generate -i swagger.yaml -g dart -o ./_swagger

class Store {
  StorePet? pet;   // Could have been Pet? Or Object?
  ... 
}

class Pet {
  String name;
  String petType;
   ...
}

class Dog { // "extends Pet" is missing !!!
  ...
}

class StorePet {
...
  String name;
  String petType;
  StorePetHuntingSkillEnum huntingSkill;
  int? packSize;
...
}

However, with a Java client target and the same specification, it looks a little better...

// java -jar openapi-generator-cli.jar generate -i swagger.yaml -g java -o ./_swagger

public class Store {
  public static final String SERIALIZED_NAME_PET = "pet";

  @SerializedName(SERIALIZED_NAME_PET)
  private StorePet pet;    /// <<<<<<<< Could have been Pet? or Object?

  @javax.annotation.Nullable
  public StorePet getPet() {
    return pet;
  }
}

public class Pet {
...
  private String name;
  protected String petType;
...
}

public class Dog extends Pet {

...
}


public class StorePet extends AbstractOpenApiSchema {

    public static class CustomTypeAdapterFactory implements TypeAdapterFactory {
    return (TypeAdapter<T>) new TypeAdapter<StorePet>() {
...
                @Override
                public StorePet read(JsonReader in) throws IOException {

... test if a cat or dog is found and call setActualInstance() with a Cat or a Dog class instance.

    }

Here, I guess you can call access Store.pet.getActualInstance() to get a Cat or Dog in Java, but not for Dart. If this a bug in the implementation?

It's also not obvious why the Java version is implemented this way. We could have had:

class Store {
  Object? pet;   // Or Pet?
  public static Store fromJson(String jsonString){
    // Figure out what class to construct with pet.petType using the schema information
    // components.schemas.Store.properties.pet.discriminator.propertyName = petType

  } 
}

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 the provided OpenAPI specification and the generator command for the Dart target, then compare the generated Store, StorePet, Pet, Cat, and Dog classes with the Java output. Done means the Dart client handles the oneOf discriminator consistently, preserving Cat or Dog deserialization for Store.pet rather than only generating a flattened StorePet union.

Written by the indexing model from the issue text.

Assessment

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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.