(global) Schema mappings
since 2025.1
Schema mappings add a new (global) mapping level. They apply only to (object, i.e. dto) schema properties.
That means the mappings is only used when the source type is used as a property type in a generated dto class.
This is (currently) only supported on the global level and only for Annotation mapping. |
Schema mappings try to solve the case where a type should be annotated, but only if is used in a generated dto object. Especially it should not annotate parameters.
The example will make this more clear.
Example
In the example OpenAPI below is a year value (<1>) that is used on the response schema and as query parameter.
openapi: 3.1.0
info:
title: schema mapping
version: 1.0.0
paths:
/foo:
get:
parameters:
- name: year
description: year parameter
in: query
required: true
schema:
type: integer (1)
format: year
responses:
'200':
description: the foo result
content:
application/json:
schema:
$ref: '#/components/schemas/Foo'
components:
schemas:
Foo:
type: object
properties:
year:
type: integer (1)
format: year
Using a typical mapping the processor will use java.time.Year
instead of a simple Integer
type in the generated code.
openapi-processor-mapping: v11
options:
package-name: generated
format-code: false
map:
types:
- type: integer:year => java.time.Year
Spring (with Jackson) may not serialize the type in the expected format by default. In case of java.time.Year
it will be String
and not a number.
To change serialization Jackson provides the JsonFormat
annotation:
@JsonFormat(JsonFormat.Shape.NUMBER_INT)
would change serialization of java.time.Year
to a number.
Adding the annotation mapping for this at the global type level
openapi-processor-mapping: v11
options:
package-name: generated
format-code: false
map:
types:
- type: integer:year => java.time.Year
- type: integer:year @ com.fasterxml.jackson.annotation.JsonFormat(shape = com.fasterxml.jackson.annotation.JsonFormat.Shape.NUMBER_INT)
would add the annotation, but not only in the dto, as wanted
package generated.model;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import generated.support.Generated;
import java.time.Year;
@Generated(value = "openapi-processor-core", version = "latest")
public class Foo {
@JsonFormat(shape = JsonFormat.Shape.NUMBER_INT)
@JsonProperty("year")
private Year year;
// ...
}
but also at the method parameter of the generated interface:
package generated.api;
import com.fasterxml.jackson.annotation.JsonFormat;
import generated.model.Foo;
import generated.support.Generated;
import java.time.Year;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Generated(value = "openapi-processor-core", version = "test")
public interface Api {
@GetMapping(path = "/foo", produces = {"application/json"})
Foo getFoo(@RequestParam(name = "year", required = false) @JsonFormat(shape = JsonFormat.Shape.NUMBER_INT) Year year);
}
That is not wanted. To avoid it, the annotation mapping should be added to the new schemas
mapping level:
openapi-processor-mapping: v11
options:
package-name: generated
format-code: false
map:
types:
- type: integer:year => java.time.Year
schemas:
- type: integer:year @ com.fasterxml.jackson.annotation.JsonFormat(shape = com.fasterxml.jackson.annotation.JsonFormat.Shape.NUMBER_INT)
This tell the processor to add it only to the generated dto class and not to the interface.
package generated.api;
import generated.model.Foo;
import generated.support.Generated;
import java.time.Year;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Generated(value = "openapi-processor-core", version = "test")
public interface Api {
@GetMapping(path = "/foo", produces = {"application/json"})
Foo getFoo(@RequestParam(name = "year", required = false) Year year);
}