Skip to content

blueprint-platform/openapi-generics

OpenAPI Generics for Spring Boot — Keep Your API Contract Intact End-to-End

Build CodeQL Release

Java Spring Boot OpenAPI Generator

License: MIT

Generics-Aware OpenAPI Contract Lifecycle
OpenAPI shouldn’t redefine your contract.
Preserve it end-to-end.


📑 Table of Contents


Why this exists (practical impact)

In most OpenAPI-based systems:

  • generics are flattened or lost
  • response envelopes are regenerated per endpoint
  • client models drift from server contracts over time

This creates hidden long-term cost:

  • duplicated DTO hierarchies
  • fragile client regeneration
  • broken assumptions across services

This project removes that entire class of problems.

Define your contract once in Java — reuse it everywhere without drift.


What’s new in 0.9.x

This is no longer a template-level customization.

It is now a contract-aligned generation system with progressive adoption.

1. Bring Your Own Contract (BYOC)

Reuse your own domain models instead of generating them:

<!-- Map your DTOs to existing contract classes -->
<additionalProperties>
  <additionalProperty>
    openapiGenerics.responseContract.CustomerDto=io.example.contract.CustomerDto
  </additionalProperty>
</additionalProperties>

Result:

  • no duplicated DTOs
  • full control over model ownership

2. Progressive adoption (client-side only)

Switch generation modes through the client build configuration:

<openapi.generics.skip>true</openapi.generics.skip>
Mode Behavior
false (default) Contract-aware generation
true Standard OpenAPI generation

3. Deterministic build pipeline

Client generation is a controlled execution system:

  • upstream templates are patched safely
  • contract semantics are injected
  • upstream drift fails the build early

4. End-to-end samples (Spring Boot 3 & 4)

Full pipelines are included:

  • Spring Boot 3
  • Spring Boot 4
  • producer → client → consumer

Browse:


Real usage (what you actually do)

You do NOT copy code from this repo.

You only add two building blocks.

Server (producer)

<dependency>
  <groupId>io.github.blueprintplatform</groupId>
  <artifactId>openapi-generics-server-starter</artifactId>
  <version>0.9.0</version>
</dependency>

Client (consumer)

<parent>
  <groupId>io.github.blueprintplatform</groupId>
  <artifactId>openapi-generics-java-codegen-parent</artifactId>
  <version>0.9.0</version>
</parent>

Optional:

<openapi.generics.skip>true</openapi.generics.skip>

Quick start (2 minutes)

  1. Run a sample producer (Spring Boot 3 or 4):
cd samples/spring-boot-3/customer-service
mvn clean package
java -jar target/customer-service-*.jar

Verify:


  1. Generate a client from the same pipeline:
cd samples/spring-boot-3/customer-service-client
mvn clean install

  1. Inspect generated output:
public class ServiceResponsePageCustomerDto
    extends ServiceResponse<Page<CustomerDto>> {}
  • No duplicated envelope
  • Generics preserved
  • Contract reused end-to-end

Note: Equivalent pipelines exist under samples/spring-boot-4/... for Spring Boot 4.


Contract lifecycle model

Java Contract (SSOT)
        ↓
OpenAPI (projection)
        ↓
Generator (enforcement)
        ↓
Client (contract-aligned)

OpenAPI is a projection — not the source of truth.


Core idea

The response envelope is a shared contract, not a generated model.

ServiceResponse<T>

Supported:

ServiceResponse<T>
ServiceResponse<Page<T>>

Other cases follow standard OpenAPI behavior.


System Architecture Overview

OpenAPI Generics contract-first architecture flow


Dive deeper

Explore internal architecture and design decisions:


Proof — before vs after

Before

class ServiceResponsePageCustomerDto {
  PageCustomerDto data;
  Meta meta;
}

After

public class ServiceResponsePageCustomerDto
    extends ServiceResponse<Page<CustomerDto>> {}

Design guarantees

  • ✔ Contract identity is preserved
  • ✔ Generics are preserved (within supported scope)
  • ✔ Client generation is deterministic
  • ✔ External models are reusable
  • ✔ Upstream drift is detected early

Modules


References


Contributing

Contributions are welcome — especially:

  • architectural discussions
  • real-world usage feedback
  • edge cases and integration insights

If you're evaluating or using the project, your perspective is valuable.

👉 Open an issue: https://github.com/blueprint-platform/openapi-generics/issues
👉 Start a discussion: https://github.com/blueprint-platform/openapi-generics/discussions


License

MIT — see LICENSE


Barış Saylı GitHub · Medium · LinkedIn