OpenAPITools / OpenAPITools/openapi-generator

[BUG] Kotlin generator: generateOneOfAnyOfWrappers=true leads to broken code

Open
#20,199 2 comments 5 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Issue: Bug
Dominant language
Java
Stars
26.8k
Forks
7.7k
PR merge metrics
PR metrics pending

Description

I would like to reopen this issue, since your fix in the version 7.10.0 did not do the job. The variables' names are now compatible with kotlin. Thank you ver much for that!
The other error is still happening. Code gets generates with the Gson Library instead of the Moshi Library (which should be the default according to your documentation). I then tried adding the Gson dependency to the project, but then I noticed, that the generated classes do not import any Gson Classes itself and I must override the generated files to add the correct import statements.

Bildschirmfoto 2024-11-27 um 11 59 39

In theory that would work, but still should be handled by the openapi-generator, since it's not suitable to do that everytime you build.

In addition to the above mentioned issue, the auto-generated code tries to call static methods of data classes, that do not exist.

Bildschirmfoto 2024-11-27 um 16 03 08

In my scenario MeteoMapLayer is the superclass (oneOf/anyOf) with SubTypes MeteoMapImageLayer, MeteoMapTileLayer and MeteoMapGeoJsonLayer.
The validateJsonElement(..) function is only generated for MeteoMapLayer class and not it's subclasses. So this makes also sense that this does not work.

data class MeteoMapLayer(var actualInstance: Any? = null) {

    class CustomTypeAdapterFactory : TypeAdapterFactory {
        .....
    }

    companion object {
        /**
        * Validates the JSON Element and throws an exception if issues found
        *
        * @param jsonElement JSON Element
        * @throws IOException if the JSON Element is invalid with respect to MeteoMapLayer
        */
        @Throws(IOException::class)
        fun validateJsonElement(jsonElement: JsonElement?) {
            requireNotNull(jsonElement) {
                "Provided json element must not be null"
            }
            var match = 0
            val errorMessages = ArrayList<String>()
            // validate the json string with MeteoMapTileLayer
            try {
                // validate the JSON object to see if any exception is thrown
                MeteoMapTileLayer.validateJsonElement(jsonElement)
                match++
            } catch (e: Exception) {
                // Validation failed, continue
                errorMessages.add(String.format("Validation for MeteoMapTileLayer failed with `%s`.", e.message))
            }
            // validate the json string with MeteoMapImageLayer
            try {
                // validate the JSON object to see if any exception is thrown
                MeteoMapImageLayer.validateJsonElement(jsonElement)
                match++
            } catch (e: Exception) {
                // Validation failed, continue
                errorMessages.add(String.format("Validation for MeteoMapImageLayer failed with `%s`.", e.message))
            }
            // validate the json string with MeteoMapGeoJsonLayer
            try {
                // validate the JSON object to see if any exception is thrown
                MeteoMapGeoJsonLayer.validateJsonElement(jsonElement)
                match++
            } catch (e: Exception) {
                // Validation failed, continue
                errorMessages.add(String.format("Validation for MeteoMapGeoJsonLayer failed with `%s`.", e.message))
            }

            if (match != 1) {
                throw IOException(String.format("Failed validation for MeteoMapLayer: %d classes match result, expected 1. Detailed failure message for oneOf schemas: %s. JSON: %s", match, errorMessages, jsonElement.toString()))
            }
        }
    }
}
data class MeteoMapTileLayer (

    @Json(name = "data")
    val `data`: kotlin.collections.List<MeteoMapRasterizableLayerDataItem>,

    @Json(name = "disableSmoothing")
    val disableSmoothing: kotlin.Boolean? = null,

    @Json(name = "opacity")
    val opacity: kotlin.Float? = 0.8f,

    @Json(name = "insertBelowId")
    val insertBelowId: kotlin.String? = null,

    @Json(name = "insertAboveId")
    val insertAboveId: kotlin.String? = null

) {

    /**
     * 
     *
     * Values: TILES
     */
    @JsonClass(generateAdapter = false)
    enum class Type(val value: kotlin.String) {
        @Json(name = "tiles") TILES("tiles");
    }

}

I will be glad to provide you with our spec.json file if that helps you any further.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reviewing the linked issue #19942 and the Kotlin generator path responsible for generateOneOfAnyOfWrappers=true. Reproduce the generated MeteoMapLayer and subtype output, then inspect how Gson/Moshi imports and validateJsonElement calls are emitted; done means the generated code uses the documented library and compiles without manual overrides.

Written by the indexing model from the issue text.

Assessment

Tech stack
kotlin
Domain
tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.