Releases: openapi-processor/openapi-processor-base
2025.5.1
2025.5
(#291) use $ref filename without json pointer as class name
the processor did create the class name of FooResponse
based on the location as FooGetResponse200.java
if the $ref
did not have a json pointer.
It does now use the file name as class name if the $ref
does not have a json pointer, i.e. in the example below the class name will be FooResponse
instead of FooGetResponse200
.
openapi: 3.1.0 info: title: get class name from file name version: 1.0.0 paths: /foo: get: responses: '200': description: the foo result content: application/json: schema: $ref: 'FooResponse.yaml'
title: Foo Schema type: object properties: bar: type: string
(#290) mapping and bean validation annotations
the processor could produce invalid code that does not compile when combining a mapping with bean validation.
An OpenAPI (like the one below) with an integer parameter and bean validation enabled would add @DecimalMin
& @DecimalMax
annotations to the parameter in the generated code.
openapi: 3.1.0 info: title: drop bean validation annotation if mapped to unsupported type version: 1.0.0 paths: /foo: get: parameters: - in: query name: year schema: type: integer format: year minimum: 1970 maximum: 2099
This is an issue if the parameter type is mapped to a different Java type.
openapi-processor-mapping: v14 options: package-name: generated bean-validation: jakarta map: types: - type: integer:year => java.time.Year
In the example to java.time.Year
, because both annotations are not supported on java.time.Year
.
To fix this, the processor does not add it if it is not allowed.
In case the target type is not recognized automatically (and the annotations are dropped), for example on a custom java.lang.Number
implementation, it is possible to tell the processor that an annotation is valid on that type.
openapi-processor-mapping: v14 options: # ... map: # ... bean-validation: jakarta.validation.constraints.DecimalMin: - other.CustomInteger jakarta.validation.constraints.DecimalMax: - other.CustomInteger
(openapi-processor/openapi-processor-spring#365) dropping parameters by OpenAPI name
dropping parameters did only work for parameters names if the OpenAPI name was identical to the Java name, i.e. no special characters. It does now handle special characters like -
, _
or
(space).
# ... map: paths: /foo: get: parameters: - drop: foo-Param - drop: barParam
2025.4.1
(openapi-processor/openapi-processor-spring#350) enum names & validation
instead of stripping invalid characters (e.g. numbers or underscore) at the start of enum
values when converting them to a java identifier, the processor will now prefix the enums
value with a "V"
character to avoid name clashes due to the removed characters.
There is no change to the current behaviour if the enum values start with valid characters.
Warning
This may be a breaking change
To keep the old behavior, i.e., stripping the invalid characters, set the identifier-prefix-invalid-enum-start
compatibility option.
openapi-processor-mapping: v13 options: # ... compatibility: identifier-prefix-invalid-enum-start: false
this change also fixes the generated compilation issue when using string enums (options.enum-type: string
) and bean validation. Compilation failed because the generated @Values
annotation was not allowed on the generic parameter on code like this:
package io.openapiprocessor.openapi.api; import io.openapiprocessor.openapi.validation.Values; import java.util.List; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.ResponseStatus; public interface EnumApi { @ResponseStatus(HttpStatus.NO_CONTENT) @PostMapping(path = "/endpoint", consumes = {"application/json"}) void postEndpoint(@RequestBody(required = false) List<@Values(values = {"_1A", "_1B", "_2A"}) String> body); }
2025.4
replaces 2025.3. It has the same changes but with a different configuration for package names from location.
(#115) package names from location
it may not behave nicely if the expected configuration requirements are not met. It also works only with the INTERNAL OpenAPI parser (which is the default).
The package-names from location feature allows the processor to create package names based on the file location of $ref’erenced parts of the OpenAPI description.
This gets enabled by setting the package-names:location
option.
openapi-processor-mapping: v13 options: # package-name: io.openapiprocessor.sample # <1> package-names: base: io.openapiprocessor.openapi # <2> # this enables package generation from the endpoint $ref file location location: io.openapiprocessor.samples # <3>
<1> the shortcut for setting package-names.base
. If location based packages should be used, setting package-names.base
is preferred.
<2> this is the base package for all generated code. This is identical to the current behaviour (i.e. package-name
). Any file the is not below package-names.location
will be generated with this as the base package.
<3> package-name.location
is the parent package name of the project's target packages. If the processor finds a file ref'erenced from the main OpenAPI in a subpackage of package-name.location
the generated sources will be generated with that package.
Here is an example layout to show what this is about.
The OpenAPI description of the endpoint foo
is placed into the package
where it will be implemented. The generated interface and resources get the package io.openapiprocessor.samples.foo
.
The example shows only the controller implementation but it could also contain service and repositories used to handle the foo
endpoint. That way everything related to that endpoint is in one place.
sample \---- src +---- api | +---- mapping.yaml | \---- openapi.yaml \---- main +---- kotlin | +---- io | | \---- openapiprocessor | | \---- samples | | +---- foo | | | +---- FooController.kt | | | +---- foo.yaml | | | \---- resources.yaml | | \---- bar | | \---- ... \---- resources \---- application.properties
The main OpenAPI file will look something like this:
# openapi.yaml openapi: 3.1.0 info: title: openapi-processor sample api version: 1.0.0 servers: - url: "https://openapiprocessor.io/{path}" variables: path: default: api paths: /foo: $ref: '../main/kotlin/io/openapiprocessor/samples/foo/foo.yaml' # <1>
<1> foo.yaml
(the path item of foo
) is $ref`erenced from the main OpenAPI description.
# io/openapiprocessor/samples/foo/foo.yaml post: tags: - foo summary: echo a Foo. description: simple sample endpoint requestBody: $ref: 'resources.yaml#/FooBody' responses: '200': description: foo content: application/json: schema: $ref: 'resources.yaml#/Foo' # <2>
<2> and $references the resource.yaml
in the same folder that describes the payload resource.
The package name of the foo endpoint files is io.openapiprocessor.samples.foo
and the nearest parent package is io.openapiprocessor.samples
. This is then the package-name.location
option value.
It is possible to use io.openapiprocessor
or even io
as the parent package.
The generated files will still go to the output folder of the used build tool. No change there apart from the package names.
See also the spring-mvc-boot-4-packages-kt for an example setup.
(openapi-processor/openapi-processor-spring#339) generate response status annotation
the processor does now automatically generate a response status annotation for success responses (i.e., 2xx) not equal to 200.
Warning
This will conflict with manually added response status annotations.
To keep the old behavior, i.e., no automatically added annotations, set result-status: false
on the global mapping level.
It is configured by adding it to the mapping section of the configuration file. It is available on all levels, i.e., global, endpoint and endpoint method.
openapi-processor-mapping: v13 options: # ... map: # result-status: true is the default # setting it to false on the global level disables it result-status: false paths: # enable it for a specific endpoint /foo: result-status: true # ... or for a specific method of an endpoint #get: # result-status: true
example:
openapi: 3.1.0 info: title: sample api version: 1.0.0 /nop: get: tags: - nop summary: response status description: adds status for success other than 200 responses: '204': description: no content
generates (with the framework specific annotations):
package generated.api; import annotation.Mapping; import annotation.Status; import generated.support.Generated; @Generated(value = "openapi-processor-core", version = "test") public interface NopApi { /** response status adds status for success other than 200 */ @Status(204) @Mapping("/nop") void getNop(); }
2025.3
deprecated, see 2025.4
(#115) generate code into packages
this is experimental
it may not behave nicely if the expected configuration requirements are not met. It also works only with the INTERNAL OpenAPI parser (which is the default).
The package-name-from-path
option enables the creation of package names based on the file location of $ref’erenced parts of the OpenAPI description. The basic package-name
option must be a parent package of the target packages (see below).
openapi-processor-mapping: v13 options: package-name: io.openapiprocessor.sample package-name-from-path: true
Here is an example layout to show what this is about.
The OpenAPI description of the endpoint foo
is placed into the package
where it will be implemented. The generated interface and resources get the package io.openapiprocessor.samples.foo
.
The example shows only the controller implementation but it could also contain service and repositories used to handle the foo
endpoint. That way everything related to that endpoint is in one place.
sample \---- src +---- api | +---- mapping.yaml | \---- openapi.yaml \---- main +---- kotlin | +---- io | | \---- openapiprocessor | | \---- samples | | +---- foo | | | +---- FooController.kt | | | +---- foo.yaml | | | \---- resources.yaml | | \---- bar | | \---- ... \---- resources \---- application.properties
The main OpenAPI file will look something like this:
# openapi.yaml openapi: 3.1.0 info: title: openapi-processor sample api version: 1.0.0 servers: - url: "https://openapiprocessor.io/{path}" variables: path: default: api paths: /foo: $ref: '../main/kotlin/io/openapiprocessor/samples/foo/foo.yaml' # <1>
<1> foo.yaml
(the path item of foo
) is $ref`erenced from the main OpenAPI description.
# io/openapiprocessor/samples/foo/foo.yaml post: tags: - foo summary: echo a Foo. description: simple sample endpoint requestBody: $ref: 'resources.yaml#/FooBody' responses: '200': description: foo content: application/json: schema: $ref: 'resources.yaml#/Foo' # <2>
<2> and $references the resource.yaml
in the same folder that describes the payload resource.
The package name of the foo endpoint files is io.openapiprocessor.samples.foo
and the nearest parent package is io.openapiprocessor.samples
. This is then the package-name
option value.
It is possible to use io.openapiprocessor
or even io
as the parent package.
Important is that the parent package is shorter than the target package and that the target package starts with the parent package.
The generated files will still go to the output folder of the used build tool. No change there apart from the package names.
(openapi-processor/openapi-processor-spring#339) generate response status annotation
the processor does now automatically generate a response status annotation for success responses (i.e., 2xx) not equal to 200.
Warning
This will conflict with manually added response status annotations.
To keep the old behavior, i.e., no automatically added annotations, set result-status: false
on the global mapping level.
It is configured by adding it to the mapping section of the configuration file. It is available on all levels, i.e., global, endpoint and endpoint method.
openapi-processor-mapping: v13 options: # ... map: # result-status: true is the default # setting it to false on the global level disables it result-status: false paths: # enable it for a specific endpoint /foo: result-status: true # ... or for a specific method of an endpoint #get: # result-status: true
example:
openapi: 3.1.0 info: title: sample api version: 1.0.0 /nop: get: tags: - nop summary: response status description: adds status for success other than 200 responses: '204': description: no content
generates (with the framework specific annotations):
package generated.api; import annotation.Mapping; import annotation.Status; import generated.support.Generated; @Generated(value = "openapi-processor-core", version = "test") public interface NopApi { /** response status adds status for success other than 200 */ @Status(204) @Mapping("/nop") void getNop(); }
2025.2
(openapi-processor/openapi-processor-spring#328) support endpoint with different responses for different status codes
For the example below, versions before 2025.2 would pick Bar
(the last response) as the return type for the getFooApplicationJson()
endpoint method. This doesn't work because the method must be able to return Foo
or Bar
too.
To make this work it will now use Object
as return type.
openapi: 3.1.0 info: title: test multiple success responses version: 1.0.0 paths: /foo: get: description: endpoint with multiple success responses responses: '200': description: success content: application/json: schema: $ref: '#/components/schemas/Foo' '202': description: another success content: application/json: schema: $ref: '#/components/schemas/Bar' components: schemas: Foo: type: object properties: foo: type: string Bar: type: object properties: bar: type: string
(#247) marker interface for responses
openapi-processor/openapi-processor-spring#328 handles multiple response objects by using Object
as result type. An Object return type is obviously not very descriptive. It is impossible to know from the interface which results are possible.
To improve on that situation the processor can generate a marker interface that is more descriptive and helps with navigation in the IDE.
Generation of the marker interface is enabled by adding the response-interface
option:
openapi-processor-mapping: v12 options: package-name: ... # ... response-interface: true
The marker interface is an empty interface and its name is derived from the http method, path and content type to create a unique name.
If the response type (e.g. Foo from the above example OpenAPI) is used on multiple endpoints with multiple success response status it will implement multiple marker interfaces.
package generated.model; import com.fasterxml.jackson.annotation.JsonProperty; import generated.support.Generated; @Generated(value = "openapi-processor-core", version = "test") public class Foo implements GetFooApplicationJsonResponse /* , .. more interfaces if Foo is used on multiple endpoints */ { @JsonProperty("foo") private String foo; // ... }
That way it is possible to find the possible result type by navigating to the implementations of the marker interface.
parse drop mapping (openapi-processor/openapi-processor-spring#327) drop OpenAPI parameter
It is now possible to drop a parameter given in the OpenAPI description from the generated code. This may be useful if a parameter is for example handled by a request filter and therefore is not needed in the endpoint method anymore.
To drop a parameter add a parameters/drop
entry with the name of the parameter to drop it:
openapi-processor-mapping: v12 options: package-name: generated map: paths: /foo: parameters: - drop: foo
Even if it is possible to add it at the global level, it is best used at the endpoint level.
(#253) result-style
the result-style
option is now handled on all levels (global, endpoint, http method) and not just on the global level.
(openapi-processor/openapi-processor-spring#331) formatter selection
the processor didn't use the new formatter selection, it does now properly handle google
& eclipse
(no need to for extra jdk configuration) values.
openapi-processor-mapping: v12 options: package-name: # ... format-code: false # disable code formatter format-code: true # use default google code formatter format-code: google # use google code formatter, i.e. the same as "true" format-code: eclipse # use eclipse code formatter
2025.1.1
(#237) fix mapping.yaml
json schema
format-code
did restrict the type to boolean
which does not work for the allowed values google
& eclipse
. this caused a warning on processing.
(#238) javadoc
javadoc @param
generation would use a wrong parameter name if the property name was not a valid java identifier.
/** * this is the <em>Foo</em> schema description * * @param fooBar <em>property</em> description - * @param enum enum <em>property</em> description + * @param aEnum enum <em>property</em> description */ @Generated(value = "openapi-processor-core", version = "test") public record Foo( @JsonProperty("foo-bar") String fooBar, @JsonProperty("enum") FooEnum aEnum ) {}
2025.1
(#230) do not generate accessors of pojos
It is now possible to disable generation of accessor methods on pojo dtos. The properties are still private
. This is only useful in combination with an object annotation mapping that adds the accessors. For example lombok.Getter
& lombok.Setter
.
openapi-processor-mapping: v11 options: package-name: generated model-type: default # i.e. pojo model-accessors: false # only used if model-type is default map: types: - type: object @ lombok.Getter - type: object @ lombok.Setter
package io.openapiprocessor.openapi.model; import com.fasterxml.jackson.annotation.JsonProperty; import io.openapiprocessor.openapi.support.Generated; import java.util.UUID; import lombok.Getter; import lombok.Setter; @Getter @Setter @Generated(value = "openapi-processor-spring") public class Foo { @JsonProperty("id") private UUID id; }
(#225) schema mappings
It is now possible to restrict annotation mappings to schema properties by using schema level mappings. Schema mappings are only supported at the global 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)
The schema mapping will tell the processor to apply the annotation only on dto properties:
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; // ... }
and not to the api endpoint method parameter:
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); }
(#8) alternative code formatter
experimental (whatever is the use of formatting the generated code anyway.. ;-)
the current code formatter google-java-format uses internal java classes which requires additional configuration.
To avoid this additional configuration openapi-processor now supports the eclipse code formatter.
To support this the format-code
option accepts two new values: google
and eclipse
.
openapi-processor-mapping: v11 options: package-name: # ... format-code: false # disable code formatter format-code: true # use default google code formatter format-code: google # use google code formatter, i.e. the same as "true" format-code: eclipse # use eclipse code formatter
(openapi-processor/openapi-processor-spring#323) null pointer with enum in record with javadoc
fixed a null pointer exception generating javadoc for an enum type property.
javadoc improvement
improved javadoc generation for $ref
with description
.
# OpenAPI document components: schemas: Foo: description: > this is the *Foo* schema description type: object properties: foo-bar: description: > *property* description type: string enum: description: > # <1> enum *property* description $ref: '#/components/schemas/FooEnum' FooEnum: description: "this is an *enum* description" type: string enum: ['foo', 'bar']
javadoc generation now handles a description
(<1>) at $ref
elements.
For the given OpenAPI description above the pojo for Foo
will now look like this
package generated.model; import com.fasterxml.jackson.annotation.JsonProperty; import generated.support.Generated; /** * this is the <em>Foo</em> schema description */ @Generated(value = "openapi-processor-core", version = "test") public class Foo { /** * <em>property</em> description */ @JsonProperty("foo-bar") private String fooBar; /** * enum <em>property</em> description */ @JsonProperty("enum") private FooEnum aEnum; // ... }
And for the record variant:
package generated.model; import com.fasterxml.jackson.annotation.JsonProperty; import generated.support.Generated; /** * this is the <em>Foo</em> schema description * * @param fooBar <em>property</em> description * @param enum enum <em>property</em> description */ @Generated(value = "openapi-processor-core", version = "test") public record Foo( @JsonProperty("foo-bar") String fooBar, @JsonProperty("enum") FooEnum aEnum ) {}
2024.7
(#9) trace mapping lookup
the processor can now create a log of the mapping lookup. It may help to understand failing mappings.
It adds two new options to control the logging.
openapi-processor-mapping: v10 options: package-name: # ... map: # ... logging: mapping: true mapping-target: stdout
logging.mapping
enables the logging of the mapping lookups. mapping-target
set the output channel. Simplest is to use stdout
. The other possible value is logger
. See the logging documentation for a more detailed description.
(#188) minimum/maximum and their exclusive version did not work for OpenAPI 3.1
actually that was an issue in the OpenAPI parser openapi-processor/openapi-parser#114