Server-Side Adoption
Publish a generics-aware OpenAPI document from your Spring Boot service without changing runtime behavior.
This guide explains how to enable OpenAPI Generics on the producer side.
For client generation, see Client-Side Adoption.
For implementation details, see Architecture.
Contents
- Quick Start
- What the Starter Does
- Supported Controller Shapes
- BYOE — Bring Your Own Envelope
- Verification
- Further Reading
Quick Start
Add the starter:
<dependency>
<groupId>io.github.blueprint-platform</groupId>
<artifactId>openapi-generics-server-starter</artifactId>
<version>1.2.0</version>
</dependency>
Write controller methods normally:
@GetMapping("/{id}")
public ResponseEntity<ServiceResponse<CustomerDto>> getCustomer(...) {
return ResponseEntity.ok(ServiceResponse.of(service.findById(id)));
}
Container payloads are supported as well:
ServiceResponse<List<CustomerDto>>
ServiceResponse<Set<CustomerDto>>
ServiceResponse<Page<CustomerDto>>
Application-defined generic containers are also supported when registered through the optional openapi-generics.containers configuration.
What the Starter Does
The starter runs only when Springdoc generates an OpenAPI document, for example:
/v3/api-docs
/v3/api-docs.yaml
It:
- discovers supported generic response contracts
- projects wrapper and container metadata into OpenAPI
- publishes OpenAPI Generics vendor extensions
- validates the generated contract metadata
It does not:
- intercept HTTP requests
- change runtime serialization
- modify controller behavior
Projection pipeline:
Java Contract
↓
Response Introspection
↓
OpenAPI Projection
↓
Vendor Extensions
↓
Validated OpenAPI Document
Supported Controller Shapes
Built-in contracts:
ServiceResponse<T>
ServiceResponse<List<T>>
ServiceResponse<Set<T>>
ServiceResponse<Page<T>>
BYOE envelopes support the same response shapes.
Application-defined generic containers (for example Paging<T> or Window<T>) participate in the same projection pipeline when registered through configuration.
Asynchronous wrappers are unwrapped automatically, including:
CompletionStage<T>
Future<T>
DeferredResult<T>
WebAsyncTask<T>
BYOE — Bring Your Own Envelope
Use your own response envelope instead of ServiceResponse<T>.
Configure the envelope and, optionally, register application-defined generic containers:
openapi-generics:
envelope:
type: io.example.contract.ApiResponse
# Optional
containers:
- type: io.example.contract.Paging
item-property: content
- type: io.example.contract.Window
item-property: items
The configured envelope becomes the published contract while preserving the same projection model.
Configured generic containers are optional. When registered, they participate in the same projection pipeline as the built-in List<T>, Set<T>, and platform-provided Page<T> container types.
This allows generated clients to reconstruct both built-in and application-defined generic container contracts through the same deterministic model.
Verification
After starting the application, verify that the generated OpenAPI document contains OpenAPI Generics metadata.
Built-in container example:
x-api-wrapper: true
x-api-wrapper-datatype: PageCustomerDto
x-data-container: Page
x-data-container-type: io.github.blueprintplatform.openapi.generics.contract.paging.Page
x-data-item: CustomerDto
Application-defined container example:
x-api-wrapper: true
x-api-wrapper-datatype: PagingCustomerDto
x-data-container: Paging
x-data-container-type: io.example.contract.Paging
x-data-item: CustomerDto
Infrastructure schemas that are contract-owned or externally provided should also be marked with:
x-ignore-model: true
These metadata allow the client generator to reconstruct the original Java contract deterministically.