OpenAPITools / openapi-generator

OpenAPI Generator allows generation of API client libraries (SDK generation), server stubs, documentation and configuration automatically given an OpenAPI Spec (v2, v3)
https://openapi-generator.tech
Apache License 2.0
21.94k stars 6.59k forks source link

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

Open notizklotz opened 3 years ago

notizklotz commented 3 years ago

Bug Report Checklist

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.

ena1106 commented 3 years ago

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

nicolaes commented 2 years ago

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

petermetz commented 1 year ago

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.

timurgen commented 2 months ago

This is still an issue with incorrectly generated constructor , would it be fixed someday?

petermetz commented 2 months ago

@timurgen Sorry, I'm struggling with workload. I'll get around to it eventually but not sure when I'll have time to update the PR. If you'd like I can invite you as a collaborator to my fork and you can take it all the way based on the most recent feedback (which was reasonable change requests IMO I just don't have the time right now).

Oh wait this is a different PR that is not mine, nvm. :-)