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

[BUG][KOTLIN-SPRING] Constructor call generated for interface supertypes if using inheritance/discriminator

Open notizklotz opened this issue 4 years ago • 2 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

If the parent of a type is generated as interface the subtype is generated with a constructor call to the parent interface which doesn't compile:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type", visible = true)
@JsonSubTypes(
      JsonSubTypes.Type(value = SubtypeA::class, name = "subtypeA"),
      JsonSubTypes.Type(value = SubtypeB::class, name = "subtypeB")
)
interface ParentSchema{
        val id: kotlin.String
        val type: DiscriminatingType
}

data class SubtypeA(

    @get:NotNull  
    @field:JsonProperty("id") override val id: kotlin.String,

    @get:NotNull  
    @field:Valid
    @field:JsonProperty("type") override val type: DiscriminatingType,

    @field:JsonProperty("subtypeAproperty") val subtypeAproperty: kotlin.Int? = null
) : ParentSchema(){
  
}

Note: ParentSchema(). The () prevent compilation

openapi-generator version

openapi-generator-maven-plugin:5.0.0

OpenAPI declaration file content or url

Sample spec

Related issues/PRs

Similar: #3587

Suggest a fix

I worked around it by removing the () from dataClass.mustache. This wouldn't work if the parent is a class.

notizklotz avatar Jan 07 '21 10:01 notizklotz

Thank you for the workaround! 🥳 If others are using openapi-generator-maven-plugin:

  • copy dataClass.mustache and remove ().
  • In the project root add a folder called openapi-generator-templates with the corrected mustache template.
  • In the plugin configuration (NOT configOptions) add: <templateDirectory>${project.basedir}/openapi-generator-templates</templateDirectory>

ena1106 avatar Aug 10 '21 15:08 ena1106

This is fixed in 5.4.0. See #11166 and #8687.

nicolaes avatar Aug 03 '22 12:08 nicolaes

The problem with the fix is that it doesn't seem to work for when "additionalProperties": true makes it so that the parent class is kotlin.collections.HashMap<String, kotlin.Any> which does need the () in order to compile.

openapi.json

{
  "openapi": "3.0.3",
  "info": {
    "title": "Hyperledger Cactus Plugin - Connector Corda",
    "description": "Can perform basic tasks on a Corda ledger",
    "version": "v2.0.0-alpha.2",
    "license": {
      "name": "Apache-2.0",
      "url": "https://www.apache.org/licenses/LICENSE-2.0.html"
    }
  },
  "paths": {},
  "components": {
    "schemas": {
      "JarFile": {
        "type": "object",
        "required": ["filename", "contentBase64", "hasDbMigrations"],
        "additionalProperties": true,
        "properties": {
          "filename": {
            "type": "string",
            "nullable": false,
            "minLength": 1,
            "maxLength": 255
          },
          "hasDbMigrations": {
            "description": "Indicates whether the cordapp jar in question contains any embedded migrations that Cactus can/should execute between copying the jar into the cordapp directory and starting the node back up.",
            "type": "boolean",
            "nullable": false
          },
          "contentBase64": {
            "type": "string",
            "format": "base64",
            "nullable": false,
            "minLength": 1,
            "maxLength": 1073741824
          }
        }
      }
    }
  }
}

JarFile.kt

package org.hyperledger.cactus.plugin.ledger.connector.corda.server.model

import java.util.Objects
import com.fasterxml.jackson.annotation.JsonProperty
import javax.validation.constraints.DecimalMax
import javax.validation.constraints.DecimalMin
import javax.validation.constraints.Email
import javax.validation.constraints.Max
import javax.validation.constraints.Min
import javax.validation.constraints.NotNull
import javax.validation.constraints.Pattern
import javax.validation.constraints.Size
import javax.validation.Valid
import io.swagger.v3.oas.annotations.media.Schema

/**
 * 
 * @param filename 
 * @param hasDbMigrations Indicates whether the cordapp jar in question contains any embedded migrations that Cactus can/should execute between copying the jar into the cordapp directory and starting the node back up.
 * @param contentBase64 
 */
data class JarFile(

    @get:Size(min=1,max=255)
    @Schema(example = "null", required = true, description = "")
    @get:JsonProperty("filename", required = true) val filename: kotlin.String,

    @Schema(example = "null", required = true, description = "Indicates whether the cordapp jar in question contains any embedded migrations that Cactus can/should execute between copying the jar into the cordapp directory and starting the node back up.")
    @get:JsonProperty("hasDbMigrations", required = true) val hasDbMigrations: kotlin.Boolean,

    @get:Size(min=1,max=1073741824)
    @Schema(example = "null", required = true, description = "")
    @get:JsonProperty("contentBase64", required = true) val contentBase64: kotlin.String
) : kotlin.collections.HashMap<String, kotlin.Any>{

}

Resulting compiler error

/kotlin-spring/src/main/kotlin/org/hyperledger/cactus/plugin/ledger/connector/corda/server/model/JarFile.kt: (34, 5): This type has a constructor, and thus must be initialized here


I'm not an expert in the generator's internals. My naive idea for a more robust solution is to have an additional context variable added by the generator before the template rendering happens. Something that could be called parentCtorCallNeeded or similar which then would allow us to update dataClass.mustache to use that boolean to render () or not with 100% certainty. I'm assuming here that the generator internally should be able to figure out whether the parent class is an interface or not, but this also might be a non-trivial thing to determine, I wouldn't know.

petermetz avatar Nov 07 '23 19:11 petermetz