OpenAPI Generator Plugins — Build Custom Code Generators for Any Language
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
- How do you register a custom generator with OpenAPI Generator?
- What method overrides add custom template variables?
- How do Maven and Gradle plugins differ?
- Why must you call super.processOpts() in custom generators?
Answers:
- Create an SPI configuration file at
META-INF/services/org.openapitools.codegen.CodegenConfigcontaining the fully qualified class name of your custom generator. - Override
postProcessModels()to add custom variables to the model map passed to templates. OverrideprocessOpts()to customize template loading and supporting files. - 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.
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
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