Generate openapi‐generator flow and structure - ronreynolds/openapi-generator GitHub Wiki

NOTE - this is based on the code as of 2025-02-11 (7.12.0)

Entry points

there appear to be two main classes (and two plugins, one for maven and one for gradle) in the openapi-codegen project:

  • org.openapitools.codegen.OpenAPIGenerator#main
    • used for the openapi-generator-cli execution
    • creates and populates a io.airlift.airline.Cli.CliBuilder<OpenApiGeneratorCommand> with a series of command classes
    • it then invokes build().parse(args).run() on the builder which triggers a whole series of events
      • checks for --version or --help cmd-line args and processes them with immediate return
      • invokes one of these commands based on the command-line args passed in and @Command class annotation on each class:
        • HelpCommand - --help = Display help information about openapi-generator
        • Version - --version = Show version information used in tooling
        • ConfigHelp - --config-help = Config help for chosen language
        • ListGenerators - --list = Lists the available generators
        • Meta - --meta = Generator for creating a new template set and configuration for Codegen
        • Validate - --validate = Validate specification
        • CompletionCommand - --completion = Complete commands (for using in tooling such as Bash Completions)
        • GenerateBatch - --batch = Generate code in batch via external configs
        • Generate - --generate = Generate code with the specified generator
          • obviously this is the most interesting one
          • performs various start-up tasks (dealing with specs, logging to stderr, config files, skip-validation, logging verbosity, etc)
          • creates CodegenConfigurator and populates with various settings (including the spec, generator-name, etc)
          • final ClientOptInput clientOptInput = configurator.toClientOptInput()
            • CodegenConfig config = CodegenConfigLoader.forName(generatorSettings.getGeneratorName())
              • this is where the code-generator (which implements CodegenConfig) is actually created
              • CodegenConfigLoader is a pseudo-Classloader that will hunt for classes via a java.util.ServiceLoader to discover implementations of CodegenConfig with the name returned by generatorSettings.getGeneratorName()
              • the file modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig contains a complete list of *Codegen classes and every one of them implements org.openapitools.codegen.CodegenConfig#getName to return their specific language (e.g., "java") which, i suspect, is how the generator-name provided is mapped to the generator implementation class
          • new DefaultGenerator(isDryRun).opts(configurator.toClientOptInput()).generate(); (more or less)
            • at this point it's similar to the plugins (and probably the spring-boot server; didn't delve into that one too far)
  • org.openapitools.codegen.online.OpenAPI2SpringBoot#main
    • used for the openapi-generator-online service
  • maven plugin (org.openapitools.codegen.plugin.CodeGenMojo) maps settings into a ClientOptInput and then creates and invokes a org.openapitools.codegen.DefaultGenerator
  • gradle plugin (org.openapitools.generator.gradle.plugin.OpenApiGeneratorPlugin) appears (it's written in Kotlin which i barely read) to do much the same based on org.openapitools.generator.gradle.plugin.tasks.GenerateTask#doWork

DefaultGenerator

opts(ClientOptInput opts)

  • internalizes ClientOptInput and extracts various settings such as the io.swagger.v3.oas.models.OpenAPI and CodegenConfig
    • note, the config is actually the language-specific code-generator (e.g.,
  • preps the template engine, which may or may not be a Mustache engine; the alternative is "Handlebars" apparently
  • also preps ignored files

generate()

  • verifies that openAPI and config are set and that the generator has metadata (tho missing metadata is only logged warning)
  • configureGeneratorProperties()
    • populate more instance variables from GlobalSettings
      • GlobalSettings is actually a InheritableThreadLocal<Properties> populated initially from System.getProperties
    • process many configuration flags and performs many prep steps
    • TODO - fill in with more detail
  • configureOpenAPIInfo()
    • sets various versions, contact info, license info, etc.
  • config.processOpenAPI(openAPI)
    • config is the
  • processUserDefinedTemplates()
  • generateOpenapiGeneratorIgnoreFile()
  • generateModels(files, allModels, filteredSchemas, aliasModels)
  • generateApis(files, allOperations, allModels)
  • generateWebhooks(files, allWebhooks, allModels)
  • bundle = buildSupportFileBundle(allOperations, allModels, aliasModels, allWebhooks)
  • generateSupportingFiles(files, bundle)
  • if dryRun then just dump info to console (as error?)
  • if !dryRun and generateSupportingFiles
    • generateFilesMetadata(files)
  • config.postProcess()
  • GlobalSettings.reset()`

My Usage

my current use of the openapi-generator is via gradle-plugin configured thus:

openApiGenerate {
    inputSpec.set("$rootDir/src/main/resources/smartsheet-v2-openapi-v3.0.3.json")
    outputDir.set("$rootDir/build/generated/api")
    templateDir.set("$rootDir/src/main/resources/templates") // where the custom mustaches live...

    // packages to generate
    invokerPackage.set("$group.smartsheet")
    apiPackage.set("$group.smartsheet.api")
    modelPackage.set("$group.smartsheet.model")

    generatorName.set("java")   // language for client (duh)
    library.set("native")   // the HTTP client lib; see java-generator docs for full list

    generateApiTests.set(true)
    generateApiDocumentation.set(false)     // for now no point
    generateModelDocumentation.set(false)   // for now no point

    configOptions.set(mutableMapOf(
        "openApiNullable"         to "false", // OpenAPI Jackson Nullable library (not needed?)
        "hideGenerationTimestamp" to "true",  // seems kinda pointless
        "generateBuilders"        to "true",
    ))
}

Java-specific bits

because of generatorName.set("java") these parameters are eventually passed into org.openapitools.codegen.languages.JavaClientCodegen#processOpts where much of the customized processing occurs (determining which features, templates, etc to enable/disable based on the various options which have been stored into instance variables of the JavaClientCodegen instance). the hierarchy is rather deep and complicated but given the wide range of languages supported i guess it's inevitable that this project would be somewhat complicated.

  • JavaClientCodegen
    • extends AbstractJavaCodegen
      • extends DefaultCodegen
        • implements CodegenConfig
        • lots of language-agnostic settings
          • mustache settings and lambdas for pluggable functionality
          • default type mapping (which doesn't seem language-agnostic to me)
          • setting/property conversion
          • ...
      • implements CodegenConfig
        • utility method signatures and getters and setters for a huge number of settings
        • void processOpts()
      • implements DocumentationProviderFeatures
        • additional properties to select the documentation provider and the annotation library to use during code generation
      • HUGE amount of features here ... TODO
    • implements BeanValidationFeatures (Language supports generating BeanValidation-Annotations)
      • void setUseBeanValidation(boolean useBeanValidation)
    • implements PerformBeanValidationFeatures (Language supports performing BeanValidation)
      • void setPerformBeanValidation(boolean performBeanValidation)
    • implements GzipFeatures
      • void setUseGzipFeature(boolean useGzipFeature)
⚠️ **GitHub.com Fallback** ⚠️