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
20.65k stars 6.29k forks source link

[BUG] Generation failed on Windows for relative $ref #10053

Open juanpablo-santos opened 2 years ago

juanpablo-santos commented 2 years ago

Bug Report Checklist

Description

StringIndexOutOfBoundsException for relative $ref appears with a validated openapi.yaml contract, which is conformed following the description at the OpenAPI declaration file content or url section below. It seems that openapi-generator-maven-plugin 5.2.0 is hit by https://github.com/swagger-api/swagger-parser/issues/1511. Adding swagger-parser v. 2.0.27 and jackson-core 2.12.4 seems enough to fix the problem, but then the generation fails with a much more weirder StackOverflowError:

Exception in thread "main" java.lang.StackOverflowError
    at java.base/java.lang.String.lastIndexOf(String.java:1852)
    at java.base/java.lang.String.lastIndexOf(String.java:1816)
    at java.base/java.lang.String.lastIndexOf(String.java:1795)
    at org.openapitools.codegen.utils.ModelUtils.getSimpleRef(ModelUtils.java:385)
    at org.openapitools.codegen.utils.ModelUtils.hasOrInheritsDiscriminator(ModelUtils.java:1382)
    at org.openapitools.codegen.utils.ModelUtils.hasOrInheritsDiscriminator(ModelUtils.java:1403)
    at org.openapitools.codegen.utils.ModelUtils.hasOrInheritsDiscriminator(ModelUtils.java:1390)
    at org.openapitools.codegen.utils.ModelUtils.hasOrInheritsDiscriminator(ModelUtils.java:1403)
    at org.openapitools.codegen.utils.ModelUtils.hasOrInheritsDiscriminator(ModelUtils.java:1390)
    at org.openapitools.codegen.utils.ModelUtils.hasOrInheritsDiscriminator(ModelUtils.java:1403)
    at org.openapitools.codegen.utils.ModelUtils.hasOrInheritsDiscriminator(ModelUtils.java:1390)
    at org.openapitools.codegen.utils.ModelUtils.hasOrInheritsDiscriminator(ModelUtils.java:1403)
    at org.openapitools.codegen.utils.ModelUtils.hasOrInheritsDiscriminator(ModelUtils.java:1390)
    at org.openapitools.codegen.utils.ModelUtils.hasOrInheritsDiscriminator(ModelUtils.java:1403)
    at org.openapitools.codegen.utils.ModelUtils.hasOrInheritsDiscriminator(ModelUtils.java:1390)
[...]

Turning on debug to see what spec has been understood by openapi, the aforementioned StackOverflowError seems to be caused because all models inheriting from any other model are parsed like this:

[...]
      "model\\beneficiarios\\BeneficiaryContactInformationContract" : {
        "allOf" : [ {
          "$ref" : "#/components/schemas/model\\beneficiarios\\BeneficiaryContactInformationContract"
        } ],
        "properties" : {
          "email" : {
            "$ref" : "#/components/schemas/model\\beneficiarios\\BeneficiaryContactInformationContract"
          },
[...]

Not sure where or why all allOf $refs are changed to self instead of its proper parent, hence causing this error.. Note that this only happens on Windows boxes, the same contract generates the associated files OK if it is launched on an Ubuntu box.

openapi-generator version

5.2.0 (but only on Windows environments), suspect it might happen with 5.0.0 onwards.

OpenAPI declaration file content or url

openapi.yaml

openapi: 3.0.1
[...]
components:
  schemas:
Beneficiario:
      $ref: './model/beneficiarios/BeneficiarioContract.yaml#/BeneficiarioContract'

and with ./model/beneficiarios/BeneficiarioContract.yaml been something like

type: object
allOf:
  - $ref: '../common/Base.yaml#/Base'
properties:
[...]

and ./common/Base.yaml being something like

Base:
  type: object
  discriminator:
    propertyName: baseId
  properties:
    baseId:
      type: string
Generation Details

Don't know how many languages are affected by this behaviour, I stumbled with this using JavaSpring, with no fancy configuration options..

Steps to reproduce

see Description section

Related issues/PRs

Not sure if #8495 is involved.

Suggest a fix

N/A

Saljack commented 2 years ago

I can confirm that upgrading swagger-parser-v3 resolved this issue

<dependency>
  <groupId>io.swagger.parser.v3</groupId>
  <artifactId>swagger-parser-v3</artifactId>
  <version>2.0.30</version>
</dependency>

And here is the commit which fixed it https://github.com/swagger-api/swagger-parser/commit/16e499ce3e89aa9d401231f5ddb823d587216953

tJouve commented 1 month ago

Make it works by using an upgraded version of io.swagger.parser.v3:swagger-parser (2.1.22) as suggested by https://github.com/OpenAPITools/openapi-generator/issues/10053#issuecomment-1036376625

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath "org.openapitools:openapi-generator-gradle-plugin:7.5.0"
        classpath "io.swagger.parser.v3:swagger-parser:2.1.22"
    }
}
apply plugin: "org.openapi.generator"

And casting the input path to an URI make it works on Windows with absolute path.
Without casting I have the same error as @juanpablo-santos on the ref resolution


buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath "org.openapitools:openapi-generator-gradle-plugin:7.5.0"
        classpath "io.swagger.parser.v3:swagger-parser:2.1.22"
    }
}
apply plugin: "org.openapi.generator"
import org.openapitools.generator.gradle.plugin.tasks.GenerateTask

void createOpenApiGenerateTask(File input, File target) {
    String fileNameWithoutExtension = input.name.take(input.name.lastIndexOf('.'))
    String taskName = "openApiGenerate_" + fileNameWithoutExtension;
    println "Generating OpenAPI client for ${input} to ${target}"
    tasks.register(taskName, GenerateTask) {
        generatorName = "spring"
        //If path is not cast into an URI here swagger failed to resolve ref
        inputSpec = input.toURI().toString()
        outputDir = target.toString()
        modelNameSuffix = "Dto"
        configOptions = [
            useSpringBoot3     : "true",
            dateLibrary        : "java8",
            useSpringController: "true",
            interfaceOnly      : "true",
        ]
    }
    compileJava.dependsOn(taskName)
}

def dir = file("src/main/resources/openApi/")
def target = file("build/generated")
if (dir.exists() && dir.isDirectory()) {
    fileTree(dir).each { file ->
        createOpenApiGenerateTask(file,target);
    }
} else {
    println "Directory does not exist or is not a directory: ${dir}"
}

sourceSets {
    main {
        java {
            srcDirs += 'build/generated/src/main/java'
        }
    }
}

The following code should return a correct URI with the format file://C:/my_workspace but it looks like he need some help

https://github.com/OpenAPITools/openapi-generator/blob/dc81339ef1380896f3b2d2dfd5df3afef8271d3a/modules/openapi-generator-maven-plugin/src/main/java/org/openapitools/codegen/plugin/CodeGenMojo.java#L1021-L1032