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

[BUG] Kotlin DTO with object member not generated properly

Open PierreMardon opened this issue 1 year ago • 3 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
openapi-generator version

7.2.0, don't know about previous versions as this was my first attempt

OpenAPI declaration file content or url

With this schema :

openapi: 3.0.0
paths:
info:
  title: Eixample API
  description: The API for the Eixample backend.
  version: 0.1.0
servers:
  - description: Development
    url: https://api.dev.eixample.dev
components:
  securitySchemes:
    bearer:
      type: http
      scheme: bearer
      bearerFormat: JWT
  schemas:
    Geozone:
      type: object
      properties:
        geoJson:
          type: object
          description: The definition of the geometry for the geozone.
          additionalProperties: true
        id:
          type: string
          description: The unique identifier for the geozone.
          format: uuid
      required:
        - geoJson
        - id

I obtain this class:

/**
 *
 * Please note:
 * This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
 * Do not edit this file manually.
 *
 */

@file:Suppress(
    "ArrayInDataClass",
    "EnumEntryName",
    "RemoveRedundantQualifierName",
    "UnusedImport"
)

package com.heetch.common.business.repositories.eixampleApi.dto

import com.heetch.common.business.repositories.eixampleApi.dto.AllowedLocation

import kotlinx.serialization.Serializable
import kotlinx.serialization.SerialName
import kotlinx.serialization.Contextual

/**
 * 
 *
 * @param geoJson The definition of the geometry for the geozone.
 * @param id The unique identifier for the geozone.
 */
@Serializable

data class Geozone (

    /* The definition of the geometry for the geozone. */
    @Contextual @SerialName(value = "geoJson")
    val geoJson: kotlin.collections.Map<kotlin.String, kotlin.Any>,

    /* The unique identifier for the geozone. */
    @Contextual @SerialName(value = "id")
    val id: java.util.UUID,

Which causes an error on val geoJson: kotlin.collections.Map<kotlin.String, kotlin.Any> described as:

Serializer has not been found for type 'Any'. To use context serializer as fallback, explicitly annotate type or property with @Contextual
Generation Details

Gradle plugin task:

openApiGenerate {
    generatorName.set("kotlin")
    inputSpec.set("$rootDir/some.yaml")
    outputDir.set(generatedSourcesPath)
    packageName.set("some.package")
    modelPackage.set("some.package")
    configOptions.set(mapOf(
        "dateLibrary" to "java8",
        "collectionType" to "list",
        "serializationLibrary" to "kotlinx_serialization",
    ))
}
Steps to reproduce

Execute the openApiGenerate task

Related issues/PRs
Suggest a fix

Adding @Contextual to the second type of Map : kotlin.collections.Map<kotlin.String, @Contextual kotlin.Any> seems to fix the issue.

PierreMardon avatar Jan 19 '24 20:01 PierreMardon

In fact, my previous suggestion won't work. Replacing the Map with kotlinx.serialization.json.JsonObject works and seems appropriate.

PierreMardon avatar Feb 12 '24 19:02 PierreMardon

How did you doReplacing the Map with kotlinx.serialization.json.JsonObject? @PierreMardon

charlee-dev avatar Apr 23 '24 16:04 charlee-dev

@charlee-dev I'm far from being an expert so there may be a better way to do so, but as I needed multiple post-generation tweaks I implemented a copy task:

tasks.register<Copy>("postProcessDto") {
    from(generatedDtoFolder)
    into(targetDtoFolder)
    filter { line: String ->
        line
            // Fix for https://github.com/OpenAPITools/openapi-generator/issues/17658
            .replace(
                "kotlin.collections.Map<kotlin.String, kotlin.Any>",
                "kotlinx.serialization.json.JsonObject"
            )
            // We need plain old java Date
            .replace("java.time.OffsetDateTime", "java.util.Date")
    }
    dependsOn("openApiGenerate")
}

PierreMardon avatar Apr 23 '24 18:04 PierreMardon