This guide covers building, testing, and contributing to the OpenAPI Model Generator plugin.
- Project Structure
- Requirements
- Building
- Testing
- Development Workflow
- Contributing
- Versioning and Releases
- Technical Architecture
- Code Style and Standards
openapi-modelgen/
├── gradle/
│ └── libs.versions.toml # Version catalog (shared)
├── plugin/ # Main plugin implementation
│ ├── gradle/
│ │ └── libs.versions.toml # Version catalog (plugin copy)
│ ├── src/main/java/com/guidedbyte/openapi/modelgen/
│ │ ├── OpenApiModelGenPlugin.java # Core plugin with advanced optimizations
│ │ ├── OpenApiModelGenExtension.java # DSL extension with multi-spec support
│ │ ├── DefaultConfig.java # Global defaults configuration
│ │ ├── SpecConfig.java # Individual spec configuration
│ │ ├── actions/ # Task action implementations
│ │ │ ├── GenerateModelsAction.java # Core generation logic
│ │ │ └── TemplatePreparationAction.java # Template orchestration
│ │ └── services/ # Core services
│ │ ├── ConfigurationValidator.java # Configuration validation
│ │ ├── LibraryTemplateExtractor.java # Template library support
│ │ ├── TaskConfigurationService.java # Task configuration
│ │ └── TemplateCacheManager.java # Performance optimization
│ ├── src/main/resources/
│ │ ├── templateCustomizations/ # Built-in YAML customizations
│ │ │ └── spring/ # Generator-specific customizations
│ │ └── plugin-description.md # External plugin documentation
│ └── src/test/java/com/guidedbyte/openapi/modelgen/ # Comprehensive test suite
│ ├── PluginFunctionalTest.java # Unit tests with ProjectBuilder
│ ├── WorkingIntegrationTest.java # TestKit integration tests
│ ├── TemplatePrecedenceUnitTest.java # Template precedence testing
│ ├── TemplatePrecedenceTest.java # Template precedence integration tests
│ ├── LiveTemplatePrecedenceTest.java # Live template testing
│ ├── services/ # Service-specific tests
│ └── TestSummary.md # Test coverage documentation
└── test-app/ # Test application using the plugin
├── build.gradle # Plugin configuration example
└── src/main/resources/openapi-spec/ # OpenAPI specifications
├── pets.yaml # Pet store API specification
└── orders.yaml # Orders API specification
- Java 17+ (for development and runtime)
- Gradle 8.0+ (wrapper included)
- Git (for version control)
- OpenAPI Generator 7.10.0+ (provided by consumer projects)
- Gradle 8.0+ (for plugin execution)
Build the plugin:
./gradlew plugin:buildClean build:
./gradlew clean buildBuild with configuration cache:
./gradlew plugin:build --configuration-cacheThe project uses a composite build with the plugin in a separate directory:
settings.gradle:
includeBuild 'plugin' // Composite build inclusionImportant: Use includeBuild, not include 'plugin' for composite builds.
The project uses Gradle version catalogs for centralized dependency management:
gradle/libs.versions.toml (shared across composite build):
[versions]
# Security fixes - DO NOT downgrade
snakeyaml = "2.3" # Fixes CVE-2022-1471 (CRITICAL)
commons-lang3 = "3.18.0" # Fixes CVE-2025-48924 (MEDIUM)
openapi-generator = "7.14.0"
gradle-plugin-publish = "1.3.0"
lombok = "1.18.36"
[libraries]
# Plugin core dependencies
plugin-core = { group = "org.apache.commons", name = "commons-lang3", version.ref = "commons-lang3" }
snakeyaml = { group = "org.yaml", name = "snakeyaml", version.ref = "snakeyaml" }
[bundles]
plugin-core = ["plugin-core", "snakeyaml"]
plugin-test = ["junit-jupiter", "assertj-core", "mockito-core"]Version Catalogs track security-critical dependencies:
[versions]
# Security fixes - DO NOT downgrade
snakeyaml = "2.3" # Fixes CVE-2022-1471 (CRITICAL)
commons-lang3 = "3.18.0" # Fixes CVE-2025-48924 (MEDIUM)The plugin includes comprehensive testing with 247+ test methods across 27 test classes:
- Unit tests: Core functionality with ProjectBuilder
- Integration tests: Real Gradle environment with TestKit
- Template precedence tests: Comprehensive template resolution testing
- Performance tests: Incremental builds and caching validation
- Configuration validation tests: Error handling and validation
Run all tests:
./gradlew plugin:testRun with configuration cache:
./gradlew plugin:test --configuration-cacheRun specific test class:
./gradlew plugin:test --tests "PluginFunctionalTest"Run with debug output:
./gradlew plugin:test --infoProjectBuilder-based tests for fast feedback:
@Test
void testPluginAppliesCorrectly() {
Project project = ProjectBuilder.builder().build();
project.getPlugins().apply(OpenApiModelGenPlugin.class);
assertThat(project.getExtensions().findByType(OpenApiModelGenExtension.class))
.isNotNull();
}TestKit-based tests for real Gradle environment:
@Test
void testGenerateTaskCreation() {
BuildResult result = GradleRunner.create()
.withProjectDir(projectDir)
.withArguments("tasks", "--all")
.withPluginClasspath()
.build();
assertThat(result.getOutput()).contains("generatePets");
}Comprehensive template resolution testing:
@Test
void testUserTemplateOverridesCustomizations() {
// Setup user template and YAML customization
// Verify user template takes precedence
}Test application (test-app/) provides real-world testing:
# Test with sample application
cd test-app
# Generate models
./gradlew generatePets
# Generate all models
./gradlew generateAllModels
# Build with generated code
./gradlew buildPlugin test configuration:
// plugin/build.gradle
test {
useJUnitPlatform()
testLogging {
events "passed", "skipped", "failed"
exceptionFormat "full"
}
systemProperty 'test.gradle.version', gradle.gradleVersion
}- Make changes to plugin source code
- Test changes:
./gradlew plugin:test
- Test with sample app:
cd test-app ./gradlew generatePets - Verify integration:
cd test-app ./gradlew build
Requirements:
- No
Projectin Actions: UseProjectLayout,DirectoryPropertyinstead - Static Logging Only:
LoggerFactory.getLogger(Class), neverproject.getLogger() - Config vs Execution Separation: All discovery at config time, serializable objects only
- Test with
--configuration-cache: All changes must pass cache tests
Testing:
./gradlew plugin:test --configuration-cache
./gradlew plugin:build --configuration-cache
cd test-app && ./gradlew generatePets --configuration-cacheDebug plugin during test:
./gradlew plugin:test --debug-jvmDebug test application:
cd test-app
./gradlew generatePets --debugView template processing:
cd test-app
./gradlew generatePets --info | grep -i template- Read this development guide
- Check existing issues: GitHub Issues
- Run full test suite:
./gradlew plugin:test cd test-app && ./gradlew build
-
Create feature branch:
git checkout -b feature/your-feature-name
-
Make changes with tests
-
Verify tests pass:
./gradlew plugin:test --configuration-cache
-
Test with sample app:
cd test-app ./gradlew clean generateAllModels build -
Update documentation if needed
-
Create pull request with:
- Clear description
- Test coverage
- Documentation updates
- Breaking change notes
- All tests must pass
- Configuration cache compatibility maintained
- No security vulnerabilities introduced
- Documentation updated for new features
- Backward compatibility preserved (or migration path provided)
The plugin uses semantic versioning with automated git-based version detection:
# Check current version
./gradlew showVersion
# Validate version format
./gradlew validateVersion
# Create release (validates, tests, and tags)
./gradlew createRelease- Development: Work on
SNAPSHOTversions - Testing: Validate with
./gradlew validatePlugin - Release: Create tag with
./gradlew createRelease - Publish: Push tag and run
./gradlew publishPlugins
# Command line override
./gradlew build -Pversion=1.1.0
# gradle.properties override
# Uncomment version=1.1.0 in gradle.properties
# Git tag-based (automatic)
git tag v1.1.0 && ./gradlew buildGradle Plugin Portal:
./gradlew publishPluginsLocal testing:
./gradlew publishToMavenLocalResponsibilities:
- Plugin registration and lifecycle
- Task creation and configuration
- Extension registration
- Dependency management integration
Responsibilities:
- DSL configuration interface
- Defaults and spec configuration
- Configuration validation
- CLI parameter support
GenerateModelsAction:
- Core generation logic
- OpenAPI Generator integration
- Output management
TemplatePreparationAction:
- Template orchestration
- Multi-level caching
- Template precedence resolution
ConfigurationValidator:
- Configuration validation
- Error reporting
- Best practice enforcement
LibraryTemplateExtractor:
- Template library support
- JAR resource extraction
- Metadata processing
TaskConfigurationService:
- Task configuration management
- CLI parameter integration
- Configuration merging
TemplateCacheManager:
- Multi-level caching system
- Performance optimization
- Cache invalidation
Serializable Configuration:
public class SpecConfig implements Serializable {
private String inputSpec;
private String modelPackage;
// All fields must be serializable
}No Project References in Actions:
public abstract class GenerateModelsAction implements WorkAction<GenerateModelsParameters> {
// Use parameters, not direct Project references
@Override
public void execute() {
String outputDir = getParameters().getOutputDir().get();
// Implementation using parameters only
}
}Precedence Hierarchy:
- Explicit User Templates (highest precedence)
- User YAML Customizations
- Library Templates
- Library YAML Customizations
- Plugin YAML Customizations
- OpenAPI Generator Defaults (lowest precedence)
Template Discovery:
// Recursive template dependency discovery
Pattern includePattern = Pattern.compile("\\{\\{>\\s*(\\w+)\\s*\\}\\}");
Matcher matcher = includePattern.matcher(templateContent);
while (matcher.find()) {
String dependentTemplate = matcher.group(1);
extractTemplateDependency(dependentTemplate);
}Session Cache: ConcurrentHashMap for build session
Working Directory Cache: SHA-256 content validation
Global Cache: Cross-build persistence in ~/.gradle/caches/
- Lazy evaluation: Template extraction deferred until execution
- Selective processing: Only processes templates requiring customization
- Parallel processing: Thread-safe multi-spec generation
- Content-based invalidation: SHA-256 hashing for change detection
Follow standard Java conventions:
- Package naming:
com.guidedbyte.openapi.modelgen - Class naming: PascalCase
- Method naming: camelCase
- Constants: UPPER_SNAKE_CASE
Example:
public class TemplatePreparationAction implements WorkAction<TemplatePreparationParameters> {
private static final Logger LOGGER = LoggerFactory.getLogger(TemplatePreparationAction.class);
@Override
public void execute() {
// Implementation
}
}Method-call DSL:
// Use method calls, not assignment
openapiModelgen {
defaults {
outputDir "build/generated" // Method call
// outputDir = "build/generated" // Don't use assignment
}
}Test naming:
@Test
void testConfigurationValidationWithMissingInputSpec() {
// Test implementation
}Assertions with AssertJ:
assertThat(result.getOutput())
.contains("generatePets")
.doesNotContain("error");Javadoc for public APIs:
/**
* Validates the plugin configuration and reports errors.
*
* @param extension the plugin extension containing configuration
* @throws InvalidUserDataException if configuration is invalid
*/
public void validateConfiguration(OpenApiModelGenExtension extension) {
// Implementation
}README and docs:
- Use clear examples
- Include troubleshooting sections
- Provide migration guides for breaking changes
Dependency Security:
- Track security-critical dependencies in version catalogs
- Document CVE fixes and version requirements
- Never downgrade security-critical versions
Template Security:
- Validate template content
- Sanitize user inputs
- Prevent path traversal attacks
Build Security:
- No secrets in configuration
- Validate all external inputs
- Use secure defaults
By following these development guidelines, you can contribute effectively to the OpenAPI Model Generator plugin while maintaining high code quality and security standards.