2023 Releases

November 2023

  • openapi-processor-spring/micronaut 2023.6

support different enum styles

it is now possible to (globally) configure different enum types in mapping.yaml:

openapi-processor-mapping: v5

options:
  package-name: generated
  enum-type: default|string|framework

default, which is default, creates a simple java enum with all uppercase enum values. It will create the same code as previous versions.

string, simply uses String and does not create an enum class. This is useful if automatic conversion of the incoming value to a java enum value does not work. In case bean-validation is enabled the processor adds a (generated) validation annotation that verifies that the string is a valid (OpenAPI) enum value.

public interface FooApi {
    @Mapping(path = "/foo", produces = {"application/json"})
    Foo postFoo(@Parameter(name = "enum") @Values(values = {"one", "two"}) String aEnum);
}

framework, is a placeholder for framework specific enum generation, only supported by openapi-processor-spring.

It generates a Java enum class similar to the default enum type. In addition, it generates a Spring ConverterFactory that Spring can use to convert incoming enum values to its corresponding java enum value (if passed as a parameter, not as part of the body).

To enable the ConverterFactory, create a configuration class like this:

package io.openapiprocessor.samples;

import {package-name}.spring.StringToEnumConverterFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @SuppressWarnings("rawtypes")
    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverterFactory(new StringToEnumConverterFactory());
    }
}

This registration is one time task. The converter factory does create an enum converter for all generated enum classes.

There is a sample that is using different enum-type configurations (string & framework).

October 2023

  • openapi-processor-spring/micronaut 2023.5

support primitive types

it is now possible to use primitive types in mapping.yaml:

openapi-processor-mapping: v4

options:
  package-name: generated

map:
  types:
    - type: string:binary => byte[]

September 2023

  • openapi-processor-spring/micronaut 2023.4

json schema validation for OpenAPI 3.1

the processor does now run json schema validation on OpenAPI 3.1 documents.

automatically clear output directory

when called, the processor clears the target directory to avoid any left over/obsolete files from previous runs.

accept generic wildcard in mapping

it is now possible to use the generic ? in a mapping.

openapi-processor-mapping: v4
options:
  package-name: io.openapiprocessor.generated

map:
  parameters:
     - add: foo => io.openapiprocessor.GenericType<?>

Spring: missing import

Spring doesn’t have shortcut annotations, e.g. @GetMapping instead of @RequestMapping(…​, method = RequestMethod.HEAD) for the http methods HEAD, OPTIONS & TRACE.

The processor does now add the missing import of RequestMethod.

improved json schema of mapping.yaml

when using endpoint specific mappings the processor (sometimes) complained about invalid entries in the mapping.yaml. This was caused by wrong definitions in the corresponding json schema.

don’t request json schema draft

a miss-configuration of the json-schema validator caused an unnecessary network request to download a json schema (draft 7) from https://json-schema.org.

write http operations in original order

the controller endpoint methods for the http operations are written in the same order as in the OpenAPI description.

Unfortunately this doesn’t work with the swagger OpenAPI parser because it doesn’t preserve the original order.

July 2023

  • openapi-processor-spring/micronaut 2023.3

object @ annotation

Using the object keyword it is possible to add an annotation to all generated schema/model classes using a single annotation mapping:

map:
  types:
    - type: object @ lombok.Builder

The object string represents all generated object classes (i.e. schema/model classes) and will add the given annotation only at the class level:

@Builder
@Generated(...)
public class Foo {
   ...
}

java records

openapi-processor is now capable of generating java record s instead of pojos for schemas. This is a global setting in the mapping.yaml. It can either have the value default (which is default) to generate pojos or record to generate records.

openapi-processor-mapping: v4

options:
  model-type: record

With model-type: record the processor will generate record s like this:

package generated.model;

import com.fasterxml.jackson.annotation.JsonProperty;
import generated.support.Generated;

@Generated(value = "openapi-processor-core", version = "test")
public record Foo(
    @JsonProperty("bar")
    String bar
) {}

and without model-type or model-type: default it will create a simple pojo:

package generated.model;

import com.fasterxml.jackson.annotation.JsonProperty;
import generated.support.Generated;

@Generated(value = "openapi-processor-core", version = "test")
public class Foo {

    @JsonProperty("bar")
    private String bar;

    public String getBar() {
        return bar;
    }

    public void setBar(String bar) {
        this.bar = bar;
    }

}

java-format option

openapi-processor uses google-java-format to format the generated files (including javadoc). Unfortunately it depends on internal jdk packages that are strongly encapsulated since JDK 16. It is necessary to tell the jdk to export a few packages.

In theory, it is not hard to configure it but in real life it is a bit fiddly to get this working. To get started without fighting with it, the default is now false instead of true.

To (re-)enable code formatting add the format-code option to the mapping.yaml:

openapi-processor-mapping: v4

options:
  format-code: true

June 2023

  • openapi-processor-spring/micronaut 2023.2

nested generic types

It is now possible to create type mappings with nested generics types. Here are a few examples:

openapi-processor-mapping: v3

options:
  package-name: generated

map:
  types:
    - type: Foo => java.util.Map<java.lang.String, java.util.List<java.lang.String>>

  paths:
    /foo:
      responses:
        - content: application/json => java.util.Map<java.lang.String, java.lang.String>

    /foo2:
      responses:
        - content: application/json => java.util.Map<java.lang.String, java.util.List<java.lang.String>>

This is useful to map an OpenAPI dictionary description using additionalProperties to a proper java map type:

# a schema the defines a dictionary with string keys and string values
Map:
    type: object
    additionalProperties:
      type: string

annotation mapping allows class parameter

annotation mapping now accepts a java class type as parameter. It is possible to add a mapping like this:

openapi-processor-mapping: v3

map:
  types:
    - type: string:foo @ io.oap.Annotation (value = io.oap.Bar.class)

improved validation output

schema validation by the internal parser has simpler & better output based on the JSON schema basic output format. It is not perfect but it is getting better.

It will provide better help on where the error is, but it may report multiple ambiguous errors.

If a schema property uses anyOf or oneOf and all possibilities don’t match (e.g. because there is a spelling error) the validator can’t know which one was meant and complains about all of them.

An example:

the error the value does not validate against the 'false' schema at instance …​ usually means that a property has a spelling error.

If the OpenAPI allows a $ref at the same location the validator reports a second error should have a property '$ref' at instance …​ because a reference object must have a $ref property.

January 2023

  • openapi-processor-spring/micronaut 2023.1

support requestBody $ref

the processor is now able to resolve $ref s of requestBody (This works with all 3 OpenAPI parsers).

openapi: 3.1.0
info:
  title: components requestBodies
  version: '1.0'

paths:
  /foo:
    post:
      responses:
        '200':
          description: ok
          content:
            application/json:
              schema:
                type: string
      requestBody:
        $ref: '#/components/requestBodies/Foo'  (1)

components:
  requestBodies:
    Foo:
      content:
        application/json:
          schema:
            type: object
            properties:
              foo:
                type: string
1 $ref is direct child of requestBody.

annotation mapping support for simple data types

it is now possible to add an annotation mapping for simple data types (format works too):

openapi-processor-mapping: v3

map:
  types:
    - type: string:uuid => java.util.UUID
    - type: string:uuid @ annotation.Bar

openapi-processor will add it on any string:uuid property used in the generated model classes:

@Generated
public class Foo {

    @Bar
    @JsonProperty("foo")
    private UUID foo;

     // ....
}

annotation mapping support for mapped types

in the previous version an annotation mapping was lost if the type was mapped at the same time to an existing class. It will now add the annotation to the existing class if possible.

Assume the following mapping:

openapi-processor-mapping: v3

options:

map:
  types:
    - type: Foo => openapiprocessor.MappedFoo
    - type: Foo @ annotation.Bar  (1)

  parameters:
     - type: Foo @ annotation.Bar (2)

MappedFoo is a class that is not generated. Adding an annotation at the parameter level works as expected (mapping <2>). But it is not possible to add the Bar annotation directly at the class (mapping <1>):

@Bar
@Generated
public class Foo {
    // ....
}

instead, openapi-processor will add it on any MappedFoo property used in the generated model classes:

@Generated
public class FooBar {

    @Bar
    @JsonProperty("foo")
    private MappedFoo foo;

     // ....
}

bean validation v3 support

Spring Boot 3 updates bean validations to v3. In v3 the package name changed from javax to jakarta. It is now possible to select between the v2 & v3 version in the mapping.yaml.

the new mapping schema v3 adds javax and jakarta as possible values for the bean-validation option. true/false will still work as before.

# use v3 for proper validation of the mapping file
openapi-processor-mapping: v3

options:
  # no bean validation, as before
  bean-validation: false

  # enable bean validation, as before (will use `javax...`)
  bean-validation: true

  # new: enable bean validation with `javax...`
  bean-validation: javax

  # new: enable bean validation with `jakarta...`
  bean-validation: jakarta

bean validation support on mapped data types

openapi-processor now preserves bean validation annotations when the source data type is mapped to an existing class. This is most interesting for the @Valid annotation.

It adds the annotations it would add on the source data type. In previous versions the annotations got lost when the data type was mapped to an existing class. Without`@Valid` the validation would not be triggered on the mapped object.

having this OpenAPI description

openapi: 3.1.0
info:
  title: mapped bean validation
  version: 1.0.0

paths:
  /foo:
    post:
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Foo'
      responses:
        204:
          description: none

components:
  schemas:
    Foo:
      type: object
      properties:
        foo:
          type: integer
          minimum: 0

the endpoint looks like this without a mapping that replaces Foo (ignore the @Mapping/@Parameter annotations, this is pseudocode used by the integration tests):

package generated.api;

import annotation.Mapping;
import annotation.Parameter;
import generated.model.Foo;
import javax.validation.Valid;

public interface Api {

    @Mapping("/foo")
    void postFoo(@Parameter @Valid Foo body);   // has @Valid annotation

}

with a mapping that replaces Foo with Bar

openapi-processor-mapping: v3

options:
  package-name: generated
  bean-validation: true

map:
  types:
    - type: Foo => openapiprocessor.Bar

it will now generate the endpoint with a @Valid on the mapped data type.

package generated.api;

import annotation.Mapping;
import annotation.Parameter;
import javax.validation.Valid;
import openapiprocessor.Bar;

public interface Api {

    @Mapping("/foo")
    void postFoo(@Parameter @Valid Bar body);   // new: has @Valid annotation

}