Skip to content

OpenAPI Generator Plugins — Build Custom Code Generators for Any Language

DodaTech Updated 2026-06-28 5 min read

In this tutorial, you will learn about OpenAPI Generator Plugins. We cover key concepts, practical examples, and best practices to help you master this topic.

OpenAPI Generator plugins extend code generation to unsupported languages, add custom processing logic, and integrate code generation directly into Maven and Gradle build pipelines.

What You'll Learn

How to build custom OpenAPI Generator plugins: Maven and Gradle plugin configuration, writing custom codegen classes in Java, registering new generators, adding custom Mustache variables, and publishing plugins for team-wide use.

Why It Matters

No built-in generator exactly matches your framework. Custom plugins generate perfectly tailored code with your team's conventions, middleware, and deployment patterns. DodaTech built a custom generator for their internal Rust microservices framework that adds service mesh configuration and circuit breaker patterns to every generated endpoint.

Real-World Use

DodaTech's infrastructure team built a custom OpenAPI Generator plugin that generates Terraform configurations, Kubernetes manifests, and Prometheus alerting rules alongside API server stubs. A single spec update regenerates infrastructure and application code together.

flowchart LR
    A["Custom\nJava Class"] --> B["Codegen\nModule"]
    B --> C["Register\nGenerator"]
    C --> D["Plugin\nJAR"]
    D --> E["Maven/Gradle\nPlugin"]
    D --> F["CLI\nIntegration"]
    E --> G["Build Pipeline"]
    F --> H["Command Line"]
    style A fill:#fef3c7,stroke:#d97706
    style D fill:#bbf7d0,stroke:#16a34a

Maven Plugin Setup

<!-- pom.xml -->
<build>
    <plugins>
        <plugin>
            <groupId>org.openapitools</groupId>
            <artifactId>openapi-generator-maven-plugin</artifactId>
            <version>7.5.0</version>
            <executions>
                <execution>
                    <goals>
                        <goal>generate</goal>
                    </goals>
                    <configuration>
                        <inputSpec>${project.basedir}/src/main/resources/openapi.yaml</inputSpec>
                        <generatorName>python-fastapi</generatorName>
                        <output>${project.build.directory}/generated</output>
                        <configOptions>
                            <packageName>com.dodatech.orders</packageName>
                            <usePydanticV2>true</usePydanticV2>
                        </configOptions>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
# Run Maven code generation:
mvn generate-sources
echo "Expected output:"
echo "  [INFO] --- openapi-generator-maven-plugin:7.5.0:generate ---"
echo "  [INFO] Generating python-fastapi server..."
echo "  [INFO] Output: /target/generated/openapi_server/"

Gradle Plugin Setup

// build.gradle
plugins {
    id 'org.openapi.generator' version '7.5.0'
}

openApiGenerate {
    generatorName = "python-fastapi"
    inputSpec = "$rootDir/src/main/resources/openapi.yaml".toString()
    outputDir = "$buildDir/generated".toString()
    apiPackage = "com.dodatech.orders.api"
    modelPackage = "com.dodatech.orders.model"
    configOptions = [
        packageName: "orders_service",
        usePydanticV2: "true",
        asyncClient: "true"
    ]
}
# Run Gradle code generation:
gradle openApiGenerate
echo "Expected output:"
echo "  > Task :openApiGenerate"
echo "  Generating python-fastapi server..."
echo "  Output: build/generated/"

Building a Custom Plugin

// CustomGenerator.java
package com.dodatech.codegen;

import org.openapitools.codegen.*;
import org.openapitools.codegen.languages.PythonFastapiServerCodegen;
import java.util.*;

public class DodatechPythonGenerator extends PythonFastapiServerCodegen {

    public DodatechPythonGenerator() {
        super();
        outputFolder = "generated/dodatech";
        modelTemplateFiles.put("dodatech-model.mustache", ".py");
        apiTemplateFiles.put("dodatech-controller.mustache", ".py");
        embeddedTemplateDir = templateDir = "dodatech-python";
        cliOptions.add(new CliOption(
            "enableTracing",
            "Enable OpenTelemetry tracing in generated code"
        ));
    }

    @Override
    public void processOpts() {
        super.processOpts();
        if (additionalProperties.containsKey("enableTracing")) {
            supportingFiles.add(new SupportingFile(
                "tracing.mustache",
                "",
                "tracing.py"
            ));
        }
    }

    @Override
    public Map<String, Object> postProcessModels(Map<String, Object> models) {
        Map<String, Object> result = super.postProcessModels(models);
        // Add custom model data for templates
        @SuppressWarnings("unchecked")
        List<Map<String, Object>> modelList = 
            (List<Map<String, Object>>) result.get("models");
        for (Map<String, Object> model : modelList) {
            Map<String, Object> m = 
                (Map<String, Object>) model.get("model");
            m.put("hasDodatechMetadata", true);
        }
        return result;
    }
}

Registering the Plugin

# src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig
com.dodatech.codegen.DodatechPythonGenerator
# Build and use the custom plugin:
mvn clean package
echo "---"
# Expected output:
# [INFO] Building jar: target/dodatech-codegen-1.0.jar

# Use with CLI:
openapi-generator generate \
    -i openapi.yaml \
    -g dodatech-python \
    -o ./gen/ \
    --additional-properties=enableTracing=true
echo "---"
# Expected output:
# Generating with custom generator: dodatech-python
# Custom templates loaded from: dodatech-python
# Tracing module added: tracing.py

Common Mistakes

1. Not Registering the Generator

Custom generators must be registered via SPI in META-INF/services/org.openapitools.codegen.CodegenConfig. Without this file, openapi-generator cannot discover the custom generator.

2. Overriding Without Calling Super

Custom generators that extend existing generators must call super.processOpts() and super.postProcessModels() to preserve base functionality. Skipping super calls breaks template resolution.

3. Hardcoding Template Paths

Use embeddedTemplateDir = templateDir to point to templates in the resources directory. Hardcoded absolute paths break when the JAR is used on different machines or in CI environments.

4. Ignoring Cross-Platform Compatibility

Custom generators are Java code running in the OpenAPI Generator Process. Test on Linux, macOS, and Windows. File path separators and line endings differ across platforms.

5. Not Versioning Custom Plugins

Custom plugins evolve as OpenAPI Generator releases new versions. Pin both OpenAPI Generator and your plugin version in CI. Test compatibility after OpenAPI Generator upgrades.

Practice Questions

  1. How do you register a custom generator with OpenAPI Generator?
  2. What method overrides add custom template variables?
  3. How do Maven and Gradle plugins differ?
  4. Why must you call super.processOpts() in custom generators?

Answers:

  1. Create an SPI configuration file at META-INF/services/org.openapitools.codegen.CodegenConfig containing the fully qualified class name of your custom generator.
  2. Override postProcessModels() to add custom variables to the model map passed to templates. Override processOpts() to customize template loading and supporting files.
  3. Maven uses XML configuration in pom.xml and runs during the generate-sources phase. Gradle uses Groovy/Kotlin DSL and runs as a custom task. Both achieve the same result with different syntax.
  4. super.processOpts() initializes default templates, CLI options, and supporting files. Without it, the base generator's configuration is not applied and your custom generator starts with an empty configuration.

Challenge: Build a custom OpenAPI Generator plugin that extends the TypeScript Fetch generator to add retry logic, request cancellation, and API key authentication. Package it as a JAR, register it with the SPI, and verify generation works.

FAQ

What language are custom plugins written in?

Custom OpenAPI Generator plugins are written in Java. They extend existing codegen classes and are compiled into JAR files.

Can I build plugins without Java knowledge?

Building full plugins requires Java. However, you can achieve extensive customization using Mustache templates and generator options without writing any Java code.

How do I distribute a custom plugin to the team?

Package the plugin as a JAR and publish to your internal Maven repository. Team members add the JAR as a dependency or place it in the OpenAPI Generator classpath.

Do plugins work with the CLI and build tools?

Yes. Once registered via SPI, custom plugins work with the CLI, Maven plugin, Gradle plugin, and any other OpenAPI Generator client.

How do I debug a custom plugin at runtime?

Use --log-level debug. Add System.out.println statements in your Java code. Attach a debugger to the JVM process running openapi-generator.

Mini Project

Create a custom generator plugin that extends python-flask to add health check endpoints, structured JSON logging, and request ID middleware. Register it with SPI, build the JAR, and verify it generates server stubs with the enhanced features.

What's Next

OpenAPI Diff — compare API specifications and manage changes.

CI/CD Codegen — integrate code generation into CI/CD pipelines.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro