swagger-codegen-generators icon indicating copy to clipboard operation
swagger-codegen-generators copied to clipboard

[Java] Issue with OneOf types

Open msmerc opened this issue 2 years ago • 0 comments

If we have an API definition like so:

components:
  schemas:
    Foo:
      type: object
      properties:
        foo:
          type: string
    Bar:
      type: object
      properties:
        bar:
          type: string
    Schema:
      oneOf:
        - $ref: '#/components/schemas/Foo'
        - $ref: '#/components/schemas/Bar'

Swagger will generate an interface OneOfSchema , as well as 3 implementors: Schema, Foo, Bar.

The problem is that the APIs (and models) will refer to the empty stub class Schema, e.g.:

public Schema somethingGet(Schema body) throws ApiException {...}

The problem is you when you call this you get issues, e.g.:

var foo = new Foo();
...
api.somethingGet(foo); //doesn't compile because Foo is not a Schema.

The fix is to rename the interface to be Schema and only have 2 implementors: Foo, Bar.

I had a go at doing this myself, seems like a change to subclass SchemaHandler.processComposedSchema() for java so that it's like so:

    @Override
    protected CodegenModel processComposedSchema(CodegenModel codegenModel, ComposedSchema composedSchema, Map<String, CodegenModel> allModels) {
        List<Schema> schemas = composedSchema.getOneOf();
        //Give the composedModel the same name as the parent:
        CodegenModel composedModel = this.createComposedModel(codegenModel.getName(), schemas);
        
        if (composedModel == null) { //returns null if it's not OneOf
            schemas = composedSchema.getAnyOf();
            composedModel = this.createComposedModel(ANY_OF_PREFFIX + codegenModel.getName(), schemas);
            if (composedModel == null) {
                return null;
            }
        }

        this.addInterfaceModel(codegenModel, composedModel);
        this.addInterfaces(schemas, composedModel, allModels);

        //This is a dirty way of saying we don't want to generate the original model
        codegenModel.setClassname("X"+codegenModel.classname);
        codegenModel.setName("X"+codegenModel.name);

        return composedModel;
    }

msmerc avatar Sep 28 '21 08:09 msmerc