Skip to main content

Feature 9: Code Generation Infrastructure

Purpose: This guide provides step-by-step instructions for setting up OpenAPI Generator foundational infrastructure.

Dependencies:

Related Documents:


Overview

What This Guide Covers

Code Generation Infrastructure provides general-purpose code generation setup for future APIs:

  • OpenAPI Generator Gradle plugin configuration
  • Basic setup (generalized, not AI-specific)
  • Test with toy OpenAPI spec
  • Generated code exclusion from checkstyle

What's Included:

  • OpenAPI Generator plugin configuration
  • SourceSets configuration for generated sources
  • Toy OpenAPI spec file for testing
  • Build integration

What's NOT Included:

  • ❌ AI-specific OpenAPI spec (Text Intelligence Epic)
  • ❌ AI-specific generated code (Text Intelligence Epic)
  • ❌ AI controller implementation (Text Intelligence Epic)

Note: This guide sets up the foundational infrastructure. AI-specific usage (spec file, generated packages, controller implementation) belongs in the Text Intelligence Epic.


Prerequisites

  • Springular boilerplate setup
  • Understanding of Gradle build configuration
  • Basic understanding of OpenAPI specifications
  • Checkstyle suppressions file configured (from Code Quality guide)

Implementation Steps

Step 1: Add OpenAPI Generator Plugin

File: server/build.gradle

Purpose: Add OpenAPI Generator Gradle plugin for code generation.

Find plugins block and add:

plugins {
// ... existing plugins ...

id 'org.openapi.generator' version '7.2.0'
}

Complete plugins block example:

plugins {
id 'java'
id 'org.springframework.boot' version '3.2.0'
id 'io.spring.dependency-management' version '1.1.4'
id 'checkstyle'
id 'org.openapi.generator' version '7.2.0'
}

Why Version 7.2.0:

  • Proven version from POC
  • Stable and well-tested
  • Supports Spring Boot 3

Step 2: Configure OpenAPI Generator Task

File: server/build.gradle

Purpose: Configure OpenAPI Generator task with basic setup (generalized, not AI-specific).

Key Points:

  • ✅ Uses toy OpenAPI spec for testing
  • ✅ Generalized package names (not AI-specific)
  • ✅ Spring Boot 3 compatible
  • ✅ Interface-only generation

Add configuration (after dependencies block or in appropriate section):

openApiGenerate {
generatorName = 'spring'
inputSpec = "$projectDir/src/main/resources/api/toy-api-openapi.yml".toString()
outputDir = "$buildDir/generated-sources/openapi".toString()
apiPackage = 'com.saas.springular.common.api.generated'
modelPackage = 'com.saas.springular.common.api.generated.model'
configOptions = [
dateLibrary: 'java8',
serializationLibrary: 'jackson',
useSpringBoot3: 'true',
hideGenerationTimestamp: 'true',
openApiNullable: 'false',
interfaceOnly: 'true',
useTags: 'true'
]
}

Configuration Explanation:

  • generatorName = 'spring' - Uses Spring generator (creates interfaces, not controllers)
  • inputSpec - Path to OpenAPI spec file (toy spec for testing)
  • outputDir - Output directory for generated code
  • apiPackage - Package for generated API interfaces
  • modelPackage - Package for generated model classes
  • dateLibrary: 'java8' - Uses Java 8 date/time types
  • serializationLibrary: 'jackson' - Uses Jackson for JSON
  • useSpringBoot3: 'true' - Spring Boot 3 compatible
  • hideGenerationTimestamp: 'true' - Removes timestamp from generated code
  • openApiNullable: 'false' - No nullable annotations (simpler code)
  • interfaceOnly: 'true' - Generates interfaces only (no controller implementation)
  • useTags: 'true' - Uses OpenAPI tags for organization

Step 3: Configure SourceSets for Generated Sources

File: server/build.gradle

Purpose: Add generated sources directory to SourceSets.

Find or create sourceSets block and add:

sourceSets {
main {
java {
srcDirs += ['build/generated-sources/openapi/src/main/java']
}
}
}

Complete sourceSets configuration (if checkstyle configuration exists, merge with it):

sourceSets {
main {
java {
srcDirs = ['src/main/java']
srcDirs += ['build/generated-sources/openapi/src/main/java']
exclude '**/generated/**' // For checkstyle (exclude path patterns, not generated-sources dir)
}
}
}

Note: The exclude '**/generated/**' is for checkstyle exclusion patterns, not for SourceSets. The generated-sources directory should be included in SourceSets for compilation.


Step 4: Configure Build Dependency

File: server/build.gradle

Purpose: Ensure OpenAPI generation runs before compilation.

Add dependency (at the end of build.gradle or in appropriate section):

compileJava.dependsOn tasks.openApiGenerate

Why This Dependency:

  • Ensures generated code exists before compilation
  • Automatic generation on build
  • No manual generation step needed

Step 5: Configure Clean Task

File: server/build.gradle

Purpose: Clean generated sources on clean task.

Find clean block or create it:

clean {
delete 'build/generated-sources'
}

Complete clean configuration:

tasks.named('clean') {
delete 'build/generated-sources'
}

Why Clean Configuration:

  • Removes generated code on clean
  • Ensures fresh generation on next build
  • Prevents stale generated code

Step 6: Create Toy OpenAPI Spec File

File: server/src/main/resources/api/toy-api-openapi.yml

Purpose: Create a simple OpenAPI spec for testing the infrastructure.

Key Points:

  • ✅ Simple hello-world API
  • ✅ Not AI-specific
  • ✅ Tests infrastructure works
  • ✅ Can be replaced with actual specs later

Create file:

openapi: 3.0.3
info:
title: Toy API
version: 1.0.0
description: Simple toy API for testing OpenAPI Generator infrastructure

servers:
- url: http://localhost:8080/api
description: Local development server

paths:
/hello:
get:
tags:
- hello
summary: Hello endpoint
operationId: hello
responses:
'200':
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/HelloResponse'

components:
schemas:
HelloResponse:
type: object
properties:
message:
type: string
example: "Hello, World!"
required:
- message

Why Toy Spec:

  • Tests infrastructure without AI dependencies
  • Simple and easy to understand
  • Proves infrastructure works
  • Can be replaced/removed when actual specs are added

Verification

Step 1: Verify Code Generation Works

Run build:

./gradlew clean build

Expected Result:

  • OpenAPI Generator task runs
  • Code generated in build/generated-sources/openapi/src/main/java
  • Generated code compiles successfully
  • Build completes successfully

Check Generated Code:

ls -la server/build/generated-sources/openapi/src/main/java/com/saas/springular/common/api/generated/

Expected Files:

  • HelloApi.java (interface)
  • model/HelloResponse.java (model class)

Step 2: Verify Generated Code Compiles

Check compilation:

./gradlew compileJava

Expected Result:

  • Compilation succeeds
  • No errors related to generated code
  • Generated classes are available

Step 3: Verify Checkstyle Excludes Generated Code

Run checkstyle (after Code Quality guide is complete):

./gradlew checkstyleMain

Expected Result:

  • Checkstyle runs successfully
  • Generated code is excluded (no checkstyle errors from generated code)
  • Source code is still checked

Verify Suppressions:

  • Check config/checkstyle/checkstyle-suppressions.xml includes generated sources patterns
  • Generated code should not appear in checkstyle reports

Step 4: Verify Clean Task Works

Run clean:

./gradlew clean

Expected Result:

  • Generated sources directory is deleted
  • build/generated-sources should not exist after clean

Verify:

ls -la server/build/generated-sources/  # Should not exist or be empty

Testing

Unit Tests

No unit tests required (infrastructure setup).

Integration Tests

Verify build integration:

  • Build succeeds with OpenAPI generation
  • Generated code compiles
  • Clean removes generated code
  • Rebuild regenerates code

Verify checkstyle integration:

  • Generated code excluded from checkstyle
  • Source code still checked
  • Checkstyle passes with clean source code

Troubleshooting

Generated Code Not Found

Issue: Compilation fails with "package not found" errors.

Solution:

  1. Verify sourceSets configuration includes generated sources directory
  2. Check compileJava.dependsOn tasks.openApiGenerate is set
  3. Run ./gradlew clean build to regenerate
  4. Verify output directory path is correct

Checkstyle Fails on Generated Code

Issue: Checkstyle reports errors from generated code.

Solution:

  1. Verify checkstyle-suppressions.xml exists
  2. Check suppressions file includes generated sources patterns
  3. Verify suppressions file path in build.gradle
  4. Check generated code paths match suppressions patterns

OpenAPI Generator Task Not Running

Issue: Generated code doesn't exist after build.

Solution:

  1. Verify plugin is in plugins block
  2. Check compileJava.dependsOn tasks.openApiGenerate is set
  3. Run ./gradlew openApiGenerate manually to test
  4. Check OpenAPI spec file exists and is valid

Usage Pattern for Future APIs

When adding a new OpenAPI spec:

  1. Create spec file:

    • Place in src/main/resources/api/
    • Use descriptive name (e.g., user-service-openapi.yml)
  2. Update build.gradle:

    • Change inputSpec to new spec file path
    • Optionally update apiPackage and modelPackage for organization
    • Or create separate openApiGenerate tasks for multiple specs
  3. Build:

    ./gradlew clean build
  4. Implement generated interfaces:

    • Create controller implementing generated interface
    • Add business logic
    • Wire to service layer

Example: Multiple Specs (advanced):

tasks.register('openApiGenerateUserService', org.openapitools.generator.gradle.plugin.tasks.GenerateTask) {
generatorName = 'spring'
inputSpec = "$projectDir/src/main/resources/api/user-service-openapi.yml".toString()
outputDir = "$buildDir/generated-sources/openapi-user".toString()
apiPackage = 'com.saas.springular.common.api.user.generated'
modelPackage = 'com.saas.springular.common.api.user.generated.model'
// ... configOptions ...
}

compileJava.dependsOn tasks.openApiGenerateUserService

Next Steps

After completing this guide:

  1. Test Infrastructure - Test profile configuration

For Text Intelligence Epic:

  • This infrastructure will be used to generate AI service API interfaces
  • AI-specific spec file and generated code will be added in Text Intelligence implementation guides

Summary

This implementation provides:

  • Code Generation Infrastructure: OpenAPI Generator plugin configured
  • Generalized Setup: Not AI-specific, usable for any API
  • Build Integration: Automatic generation on build
  • Checkstyle Exclusion: Generated code excluded from code quality checks
  • Testing: Toy spec proves infrastructure works
  • Documentation: Pattern documented for future use

All changes provide foundational infrastructure for code generation. AI-specific usage will be added in the Text Intelligence Epic.