OpenAPI 3.2 with openapi-processor
19. October 2025
OpenAPI 3.2 was released last month. See Upgrading from OpenAPI 3.1 to 3.2 for an overview of the changes.
The newest openapi-processor-spring/micronaut 2025.6 release adds support for OpenAPI 3.2.
This article will show use of two enhancements of OpenAPI 3.2 with openapi-processor-spring:
- 
$self: it provides the base URI for resolving relative referencesIt is used here with the package-name-from-location feature and simplifies the $refs in the OpenAPI description.
- 
itemSchema: which is part of the OpenAPI sequential and streaming media types support. A bit more detail can be found in the blog article JSON Streaming in OpenAPI v3.2.0.It is used to show two sample streaming apis using Spring SseEmitterandStreamingResponseBodyand the required mapping.
the sample OpenAPI
Here is the sample OpenAPI
openapi: 3.2.0 (1)
$self: '../main/kotlin/io/openapiprocessor/samples/' (2)
info:
  title: openapi-processor-spring stream sample api
  version: 1.0.0
servers:
  - url: "https://openapiprocessor.io/{path}"
    variables:
      path:
        default: api
paths:
  /sse:
    $ref: 'sse/sse.yaml' (3)
  /jsonl:
    $ref: 'jsonl/jsonl.yaml' (3)and the project directory layout.
sample
\---- src
      +---- api
      |     +---- mapping.yaml
      |     \---- openapi.yaml
      \---- main
            +---- kotlin
            |     \---- io
            |           \---- openapiprocessor
            |                 \---- samples
            |                       +---- jsonl
            |                       |     +---- JsonlController.kt
            |                       |     \---- jsonl.yaml (4)
            |                       +---- sse
            |                       |     +---- SseController.kt
            |                       |     \---- sse.yaml (4)
            |                       \ StreamApplication.kt
            \---- resources
                  \---- application.properties
| 1 | the new OpenAPI version | 
| 2 | this sets the base uri of the openapi.yamldocument used for resolving relative references. | 
| 3 | the $selfallows to shorten the$refuris of the endpoints and avoids repeating the full relative path from theopenapi.yamlentry document.Without  openapi.yaml  | 
| 4 | the OpenAPI path items of the endpoints. Putting them in a source package makes it possible to use the package name of the location as package name for generated files. package-name-from-location describes this in more detail. | 
the streaming endpoints
We have two sample endpoints, one that provides a application/jsonl stream …
get:
  tags:
    - jsonl
  summary: stream objects
  description: endpoint has a stream response
  parameters:
    - name: source
      description: query, string
      in: query
      schema:
        type: string
  responses:
    '200':
      description: jsonl stream
      content:
        application/jsonl:
          itemSchema: (1)
            type: object
            properties:
              foo:
                type: stringand another one that provides server sent events:
get:
  tags:
    - sse
  summary: stream objects
  description: endpoint has a stream response
  parameters:
    - name: source
      description: query, string
      in: query
      schema:
        type: string
  responses:
    '200':
      description: sse
      content:
        application/json:
          itemSchema: (1)
            type: object
            properties:
              foo:
                type: string| 1 | the itemSchemais a new keyword to describe the objects of the stream. | 
mapping configuration
With Spring Boot (MVC) we will use SseEmitter as endpoint return type to send server sent events and StreamingResponseBody to send JSON lines.
To tell the processor to use those classes as result type instead of the itemSchema we use a new variant of the result mapping. Everything else in the mapping.yaml is not important for this, just look at the map: at the end :-)
openapi-processor-mapping: v15
options:
  # shortcut to package-names.base
  # package-name: io.openapiprocessor.samples
  package-names:
    # same as package-name
    base: io.openapiprocessor.openapi
    # this enables package generation from the endpoint $ref file location
    location: io.openapiprocessor.samples
  # target-dir options
  target-dir:
    # add src/resource directories to target-dir
    layout: standard
  # create a property file with server/url path (requires standard target-dir layout)
  base-path:
    server-url: 0
    properties-name: api.properties
  # generate javadoc from OpenAPI description properties
  javadoc: true
  # enable code/javadoc formatting
  format-code: true
  # generate java records
  model-type: record
map:
  paths:
    /sse:
      result: plain => org.springframework.web.servlet.mvc.method.annotation.SseEmitter (1)
    /jsonl:
      result: plain => org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody (1)| 1 | the new resultmapping: instead of providing a wrapper class with a single generic parameter, likeResponseEntitywe use an arrow mapping:
 which means, instead of the plain schema described in the OpenAPI response, use the  | 
generated code
After running the processor we will get this for the JSONL endpoint:
package io.openapiprocessor.samples.jsonl;
import io.openapiprocessor.openapi.support.Generated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
@Generated(value = "openapi-processor-spring", version = "2025.5")
public interface JsonlApi {
  /**
   * stream objects endpoint has a stream response
   *
   * @return jsonl stream
   */
  @GetMapping(path = "/jsonl", produces = {"application/jsonl"})
  StreamingResponseBody getJsonl(@RequestParam(name = "source", required = false) String source); (1)
}package io.openapiprocessor.samples.jsonl;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.openapiprocessor.openapi.support.Generated;
@Generated(value = "openapi-processor-spring", version = "2025.5")
public record JsonlGetResponse200(@JsonProperty("foo") String foo) {
}Because the itemSchema is defined inline it gets a generated name, i.e. JsonlGetResponse200.
And this for the SSE endpoint:
package io.openapiprocessor.samples.sse;
import io.openapiprocessor.openapi.support.Generated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
@Generated(value = "openapi-processor-spring", version = "2025.5")
public interface SseApi {
  /**
   * stream objects endpoint has a stream response
   *
   * @return sse
   */
  @GetMapping(path = "/sse", produces = {"application/json"})
  SseEmitter getSse(@RequestParam(name = "source", required = false) String source); (1)
}package io.openapiprocessor.samples.sse;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.openapiprocessor.openapi.support.Generated;
@Generated(value = "openapi-processor-spring", version = "2025.5")
public record SseGetResponse200(@JsonProperty("foo") String foo) {
}Again, because the itemSchema is defined inline it gets a generated name, i.e. SseGetResponse200.
the sample project
The sample project is available in the samples repository. It has a simple implementation of the two endpoints (which you should not use as reference implementation).
The sample has two HTTP client scripts (Intellij IDEA) to test each endpoint.
summary
This article used two new OpenAPI 3.2 features, $self & ìtemSchema that openapi-processor does support with the latest version. $self is used to simplify the path item $ref s and itemSchema is used to describe the streaming payloads. With a result mapping the processor generated the endpoint methods with te mapped streaming result types.