1

I am trying to use swagger-codegen to generate Java API client for a schema specification. The schema uses the vendor extension x-discriminator-value to create the inheritance model.

For example, I used the schema specification which I found as yaml here and converted to json (I wrapped the result with the "spec" root so I can send the result to the online code-generator as explained later below).

When I try to generate the Java client both locally or with the online code-generator I get that the desearilization is not done using the x-discriminator-value value. Instead, it is being done with the model name. I see this in the generated JSON.java file which contains a map from discriminator to class:

            classByDiscriminatorValue.put("PhoneSetting".toUpperCase(), PhoneSetting.class);
            classByDiscriminatorValue.put("SceneSetting".toUpperCase(), SceneSetting.class);
            classByDiscriminatorValue.put("TextSetting".toUpperCase(), TextSetting.class);

[To see this you can post the above json to https://generator.swagger.io/api/gen/clients/java and check the JSON.java file.

From what I understand, I should of gotten that the key should be the x-discriminator-value value. So for example, since the schema has:

  "SceneSetting": {
      "description": "Scene Setting",
      "x-discriminator-value": "SCENE",
      "allOf": [
        {
          "$ref": "#/definitions/SectionSetting"
        }, 

then I should have a mapping

            classByDiscriminatorValue.put("SCENE".toUpperCase(), SceneSetting.class);

instead of the classByDiscriminatorValue.put("SceneSetting".toUpperCase(), SceneSetting.class);

I would appreciate any help on the matter.

Belgi
  • 14,542
  • 22
  • 58
  • 68
  • Are you sure Swagger Codegen supports `x-discriminator-value`? The corresponding [feature request](https://github.com/swagger-api/swagger-codegen/issues/4244) is in open status. – Helen Jan 29 '20 at 12:42
  • @Helen - Thank you. Here I see it is merged: https://github.com/swagger-api/swagger-codegen/pull/4252 and there is also documentation I found at https://docs.apimatic.io/advanced/swagger-codegen-extensions/ – Belgi Jan 29 '20 at 12:46
  • @Helen If you think there is an edit that can be made to the above schema sample to make the generated Java map to have the desired result this would also be great – Belgi Jan 29 '20 at 12:51
  • That PR seems to have updated `@JsonSubTypes`, it didn't touch the mappings in the `JSON.java` file. Is migrating to OpenAPI 3.0 an option for you? It has built-in support for discriminator mappings, so that codegen will produce the result you need. – Helen Jan 29 '20 at 13:33
  • @Helen it may be possible. Can I direct me to a working example I could input to the codegen to see if it generates the correct mappings? – Belgi Jan 29 '20 at 13:46
  • Here's a full example: https://gist.githubusercontent.com/hkosova/c2942145c11e915ccc8e008ec4f2b085/raw/8511402176221aa314a132fbcb3ab4e1a09e671d/oas3-discriminator-mapping-example.yaml – Helen Jan 29 '20 at 14:06

2 Answers2

1

I would recommend migrating to OpenAPI 3.0 – it has built-in support for discriminator mapping. There are OAS2-to-OAS3 converters to help with migration, but you'll have to update the mappings manually.

In OpenAPI 3.0, discriminator mappings are specified in the parent schema (not in child schemas). The following example is in YAML for readability, you can use https://www.json2yaml.com to convert it to JSON.

openapi: 3.0.2

components:
  schemas:
    # Parent schema
    SectionSetting:
      type: object
      properties:
        ...
      discriminator:
        propertyName: PROP_NAME
        mapping:
          SCENE: SceneSetting
          ...

    # Child schema
    SceneSetting:
      description: Scene Setting
      allOf:
        - $ref: '#/components/schemas/SectionSetting'
        - ...

Make sure to use Swagger Codegen version 3.x because 2.x does not support OpenAPI 3.0. You can get the latest 3.x CLI JAR from Maven Central:
https://mvnrepository.com/artifact/io.swagger.codegen.v3/swagger-codegen-cli

Helen
  • 87,344
  • 17
  • 243
  • 314
  • Thank you so much. Can I define in in such a way that the parent takes the key ("SCENE" in our example) instead of having in explicitly written in the schema? – Belgi Jan 29 '20 at 14:38
  • 1
    Could you clarify what you mean by "such as way that the parent takes the key"? I'm sorry, I don't quite follow. Anyway, by default - if `discriminator.mapping` is not specified - the mapping is based on child schema names, same way as in OAS2 without `x-discriminator-value`. That is, it's assumed that the child schema `SceneSetting` uses the discriminator property (`PROP_NAME`) with the `"SceneSetting"` value. The `discriminator.mapping` section allows associating child schema with custom values (such as `SCENE`) of the discriminator property. – Helen Jan 29 '20 at 15:02
  • Thank you very much for the detailed explanation! – Belgi Jan 29 '20 at 16:21
  • Thank you very much for the detailed explanation! In our example, I meant that instead of writing "SCENE" then I could specify that the child schema has a property (in our example it is named "x-discriminator-value" but disregard any meaning this name has) that contains the "SCENE" key. In this way we would not need to specify a list of mappings containing a mapping for each child schema, rather the mapping will always be from the child schema property value (the x-discriminator-value value in our case) to the child schema ("SceneSetting") – Belgi Jan 29 '20 at 16:26
  • For instance if we could state in the parent schema something like "ChildProprtyNameForMapping: x-discriminator-value" – Belgi Jan 29 '20 at 16:29
  • This is not possible and, frankly, I don't see the benefit of such structure. Currently the parent schema's `dscriminator.mapping` section contains both the name of the discriminator property and value-to-child-schema mappings. Keeping things in one place makes maintenance easier. In your proposal, the mappings would be split across multiple places - the name of the discriminator property in one place, and the values of that property in other places. And if the property itself is defined as an enum, you'd have to update the values in multiple places rather than just in the parent schema. – Helen Jan 29 '20 at 17:50
0

Using the vendor extension x-discriminator-value on old Swagger 2 is coupled with multiple restrictions.

See CodegenDiscriminator.java on the openapi-generator project for more information:

// legacyDiscriminatorBehavior == True, this contains:
// - the name to schema map info in the discriminMappedModelator mapping entry in your openapi spec AND
// - x-discriminator-value mappings in child oneOf + anyOf schemas + descendant schemas that allOf inherit self schema AND
// - descendant schemas that allOf inherit self schema AND
// - child oneOf + anyOf schemas

Sven Döring
  • 3,927
  • 2
  • 14
  • 17