Skip to content

Releases: openapi-processor/openapi-processor-base

2025.4.1

03 Jul 06:13
Compare
Choose a tag to compare

(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

22 Jun 15:15
Compare
Choose a tag to compare

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

09 Jun 12:51
Compare
Choose a tag to compare

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

21 Apr 15:35
Compare
Choose a tag to compare

(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-styleoption 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

11 Mar 07:24
Compare
Choose a tag to compare

(#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

09 Mar 15:39
Compare
Choose a tag to compare

(#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

09 Nov 18:52
Compare
Choose a tag to compare

(#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

2024.6.1

03 Oct 09:34
Compare
Choose a tag to compare

(#176) support for servers/server/url

the base-path property file name configuration wasn't handled properly.

openapi-processor-mapping: v9
options:
  base-path:
    properties-name: openapi.properties

2024.6

01 Oct 06:30
Compare
Choose a tag to compare

(#176) support for servers/server/url

it is now possible to tell the processor to generate a properties resource file with the path of a selected OpenAPI servers/server/url.

Given an OpenAPI description with a servers key:

openapi: 3.1.0
info:
  title: server url example
  version: 1.0.0

servers:
  - url: "https://openapiprocessor.io/{api}"
    variables:
      path:
        default: api

and a mapping

openapi-processor-mapping: v9
options:
  base-path:
    # false/true=0,1,2,... (default false)
    server-url: true

it will generate a properties file api.properties

openapi.base.path = /api

that can be used to configure the (Spring) context-path:

# application.properties

#spring.config.import = api.properties
server.servlet.context-path=${openapi.base.path}

Take a look at the documentation for more details.

(openapi-processor/openapi-processor-spring#288) javadoc of record

a record should have its javadoc at the record using @param s to describe the record properties.

Instead of

/**
 * this is the <em>Foo</em> schema description
 */
@Generated(value = "openapi-processor-core", version = "test")
public record Foo(
    /**
     * <em>property</em> description
     */
    @JsonProperty("foo-bar")
    String fooBar
) {}

the processor now generates:

/**
 * this is the <em>Foo</em> schema description
 *
 * @param fooBar <em>property</em> description
 */
@Generated(value = "openapi-processor-core", version = "test")
public record Foo(
    @JsonProperty("foo-bar")
    String fooBar
) {}

(openapi-processor/openapi-processor-spring#287) warn on endpoint without success response

the processor ignores endpoints that have no success response (i.e. 2xx response code). To detect this "error" at compile time the processor will now print a warning with the effected endpoint.

(#158) type annotation mapping ignored with model-name-suffix

using a mapping like this:

openapi-processor-mapping: v9
options:
  model-name-suffix: Resource

maps:
  types:
    - type: Foo @ io.openapiprocessor.Annotation()

did not add the annotation because of the model-name-suffix.

dependency updates

  • updated (internal) OpenAPI parser to 2024.4 (was 2024.3)
  • updated com.fasterxml.jackson:jackson-bom from 2.17.1 to 2.17.2
  • updated com.google.googlejavaformat:google-java-format from 1.22.0 to 1.23.0

2024.5

16 Jun 14:58
Compare
Choose a tag to compare

(#156) add request body description to javadoc

The request body description is added as @param to the generated javadoc.

openapi: 3.1.0
info:
  title: javadoc
  version: v1

paths:
  /foo:
    get:
      requestBody:
        description: this is the request body
        ...

(#152) missing @Generated

the generated Values and ValueValidator (used by enum-type string) were not annotated with @Generated.

(openapi-processor/openapi-processor-spring#271) (fix) missing import of class annotation parameter

using a .class parameter in a class annotation mapping did not add the import of the parameter class.

map:
  types:
    - type: Foo @ io.oap.ClassAnnotation(value = io.oap.Param.class)

In this example the import for Param was missing.

(openapi-processor/openapi-processor-spring#269) disable @Generated

its is now possible to disable the @Generated annotation. If it is disabled the processor will not add it to any generated type.

openapi-processor-mapping: v8

options:
  # ...

  # enable/disable generated annotation, true (default) or false.
  generated-annotation: false

(openapi-processor/openapi-processor-spring#268) control @JsonProperty annotation

By setting the json-property-annotation option is is possible to control the generation of the @JsonProperty annotation. It allows thre values: always, auto or never.

  • always: (the default) adds a @JsonProperty annotation to all properties.
  • auto: only adds a @JsonProperty annotation to a property if it is required, i.e. if the OpenAPI property name is not a valid java identifier or if a property uses the readOnly/ writeOnly (OpenAPI) flags.
  • never: never adds a @JsonProperty annotation to the properties. This may generated invalid code if the property name is not a valid java identifier.
openapi-processor-mapping: v8

options:
  # ...

  # control @JsonProperty annotation, always (default), auto, never.
  json-property-annotation: auto