openapi-generator icon indicating copy to clipboard operation
openapi-generator copied to clipboard

[BUG][java][spring] Non-compiling models generated with allOf

Open peter-janssen opened this issue 3 years ago • 0 comments

Bug Report Checklist

  • [x] Have you provided a full/minimal spec to reproduce the issue?
  • [x] Have you validated the input using an OpenAPI validator (example)?
  • [x] Have you tested with the latest master to confirm the issue still exists?
  • [x] Have you searched for related issues/PRs?
  • [x] What's the actual output vs expected output?
  • [ ] [Optional] Sponsorship to speed up the bug fix or feature request (example)
Description

When a model declares a property with type object AND it includes the allOf keyword the generated java code doesn't compile

openapi-generator version

This issue occurs with version 6.x and 7.x. But wasn't present in 5.4.0. The issue occurs when using OAS2 and OAS3.

OpenAPI declaration file content or url
FlatUser:
  type: object
  properties:
    broken:
      type: object
      properties:
        field1:
          type: string
        field2:
          type: string
  allOf:
    - $ref: '#/definitions/Names'
    - $ref: '#/definitions/Address'

Complete document

Generation Details

generation details

Steps to reproduce

See https://github.com/peter-janssen/openapi-bug/tree/allOf-bug (run .mvnw compile results in a compilation error)

[ERROR] ...demo/target/generated-sources/openapi/src/main/java/com/example/FlatUser.java:[86,56] <identifier> expected
[ERROR] ...demo/target/generated-sources/openapi/src/main/java/com/example/FlatUser.java:[88,21] illegal start of expression

This is due to the fact the generated code is incorrect:

public FlatUser putBrokenItem(String key,  brokenItem) {
  if (this.broken == null) {
    this.broken = ;
  }
  this.broken.put(key, brokenItem);
  return this;
}

This is due to the fact the broken property is now marked as a map ("isMap": true) by the generator:

 "vars" : [ {
      "openApiType" : "object",
      "baseName" : "broken",
      "getter" : "getBroken",
      "setter" : "setBroken",
      "dataType" : "Object",
      "datatypeWithEnum" : "Object",
      "name" : "broken",
      "defaultValueWithParam" : " = data.broken;",
      "baseType" : "Object",
      "jsonSchema" : "{\n  \"type\" : \"object\",\n  \"properties\" : {\n    \"field1\" : {\n      \"type\" : \"string\"\n    },\n    \"field2\" : {\n      \"type\" : \"string\"\n    }\n  }\n}",
      "exclusiveMinimum" : false,
      "exclusiveMaximum" : false,
      "required" : false,
      "deprecated" : false,
      "hasMoreNonReadOnly" : false,
      "isPrimitiveType" : true,
      "isModel" : true,
      "isContainer" : false,
      "isString" : false,
      "isNumeric" : false,
      "isInteger" : false,
      "isShort" : false,
      "isLong" : false,
      "isUnboundedInteger" : false,
      "isNumber" : false,
      "isFloat" : false,
      "isDouble" : false,
      "isDecimal" : false,
      "isByteArray" : false,
      "isBinary" : false,
      "isFile" : false,
      "isBoolean" : false,
      "isDate" : false,
      "isDateTime" : false,
      "isUuid" : false,
      "isUri" : false,
      "isEmail" : false,
      "isNull" : false,
      "isFreeFormObject" : false,
      "isAnyType" : false,
      "isArray" : false,
      "isMap" : true,
      "isEnum" : false,
      "isReadOnly" : false,
      "isWriteOnly" : false,
      "isNullable" : false,
      "isSelfReference" : false,
      "isCircularReference" : false,
      "isDiscriminator" : false,
      "vars" : [ {

This triggers this part of the pojo.mustache of the template:

  {{#isMap}}

  public {{classname}} put{{nameInCamelCase}}Item(String key, {{{items.datatypeWithEnum}}} {{name}}Item) {
    {{#vendorExtensions.x-is-jackson-optional-nullable}}
    if (this.{{name}} == null || !this.{{name}}.isPresent()) {
      this.{{name}} = JsonNullable.<{{{datatypeWithEnum}}}>of({{{defaultValue}}});
    }
    try {
      this.{{name}}.get().put(key, {{name}}Item);
    } catch (java.util.NoSuchElementException e) {
      // this can never happen, as we make sure above that the value is present
    }
    return this;
    {{/vendorExtensions.x-is-jackson-optional-nullable}}
    {{^vendorExtensions.x-is-jackson-optional-nullable}}
    {{^required}}
    if (this.{{name}} == null) {
      this.{{name}} = {{{defaultValue}}};
    }
    {{/required}}
    this.{{name}}.put(key, {{name}}Item);
    return this;
    {{/vendorExtensions.x-is-jackson-optional-nullable}}
  }
  {{/isMap}}
Related issues/PRs

#13551 could be the same bug but triggered in a slightly different manner. #11696 again very similar (but I already wrote the whole issue 😢

This might be just a duplicate. If so please close this issue.

Workaround

If the object is moved to a model the issue does not occur:

FlatUser:
  type: object
  properties:
    broken:
      $ref: '#/definitions/Broken'
  allOf:
    - $ref: '#/definitions/Names'
    - $ref: '#/definitions/Address'
...
Broken:
  type: object
  properties:
    field1:
      type: string
    field2:
      type: string

peter-janssen avatar Oct 15 '22 17:10 peter-janssen