Skip to content

Releases: openapi-processor/openapi-processor-base

2023.1.1

03 Jan 17:16
Compare
Choose a tag to compare

this fixes the bad internal openapi-parser dependency that broke 2023.1

See v2023.1 for the changes.

2023.1

02 Jan 16:50
Compare
Choose a tag to compare

#2, 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;

     // ....
}

openapi-processor/openapi-processor-spring#152, 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

openapi-processor/openapi-processor-spring#149, 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 pseudo code 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

}

2022.6

23 Dec 10:11
Compare
Choose a tag to compare

copied from openapi-processor-core

annotation mapping

annotation mappings allows to add additional annotations to an OpenAPI source type.

(this originates from openapi-processor/openapi-processor-spring#143 advanced validation support, but has changed into a more general solution)

Currently, this is available as

  • global annotation type mapping:

    it adds an annotation to the model class generated for the source type.

  • global & endpoint parameter annotation type mapping:

    it adds an annotation to a parameter of the source type. Since a request body is passed as parameter the mapping will work for it too.

The global annotation mapping should be added to the map/types or map/parameters section in the mapping.yaml.

The endpoint (http method) mapping restricts the mapping to a specific endpoint. This will go to the map/paths/<endpoint-path>/parameters section in the mapping.yaml.

The annotation type mapping is similar to other mappings and is defined like this:

- type: {source type} @ {annotation type}

Here is an examples mapping.yaml that defines additional annotations for two schemas (model classes) Foo & Bar:

openapi-processor-mapping: v2.1 # <1>

options:
  package-name: io.openapiprocessor.openapi
  bean-validation: true

map:
  types:
    - type: Bar @ io.openapiprocessor.samples.validations.Sum(24) # <2>

  parameters:
    - type: Foo @ io.openapiprocessor.samples.validations.Sum(value = 42) # <3>

      # this formats do work too <4>
      # - type: Foo @ annotation.Bar
      # - type: Foo @ annotation.Bar()
      # - type: Foo @ annotation.Bar("bar")
      # - type: Foo @ annotation.Bar(value = "bar", foo = 2)

The Sum annotation in the example is a custom bean validation but the feature itself is not limited to bean validation.

<1> use v2.1 as the mapping version to avoid validation warnings in the mapping file.
<2> the Bar mapping is using a global type annotation mapping, so the annotation is added to the generated Bar class.
<3> the Foo mapping adds the annotation to the parameter of the endpoint methods that use Foo.
<4> this is a list of examples that shows annotation parameters.

The Bar annotation mapping will produce the Bar model class with the additional annotation on the class:

@Sum(24) // <1>
public class Bar { /* ... */ }

The Foo annotation parameter mapping will produce the endpoint with the additional annotation on the Foo parameter:

    @PostMapping(/*...*/)
    Foo postFoo(@RequestBody @Sum(value = 42) @Valid @NotNull Foo body);

The full example is available in the spring validation sample.

openapi-processor/openapi-processor-spring#144, use annotation for generated code instead of comment

the processor now generates a @Generated annotation and adds it to all generated interfaces and classes instead of the text header.

Some tools recognize the @Generated annotation and exclude them from processing. For example, jacoco will automatically exclude the @Generated files from the code coverage.

this will look like this:

package io.openapiprocessor.release;

import io.openapiprocessor.release.support.Generated;
import org.springframework.web.bind.annotation.GetMapping;

@Generated(value = "openapi-processor-spring", version = "2022.6", date = "2022-09-28T18:37:33.250622+02:00")
public interface ReleaseApi {
// ...
}

Because of the longish date the code formatter will probably add a few line breaks.

Generation of the data parameter can be disabled by setting the generated-date option to false:

openapi-processor-mapping: v2.1 # <1>

options:
  package-name: io.openapiprocessor.openapi
  generated-date: false

<1> use v2.1 as the mapping version to avoid validation warnings in the mapping file.

openapi-processor/openapi-processor-spring#140 additional parameter configuration did not working in global context

using an additional parameter in the global context was not implemented.

map:
  parameters:
    - add: request => javax.servlet.http.HttpServletRequest

openapi-processor/openapi-processor-core#99 windows path handling

was broken since 2022.5

2022.5

23 Dec 10:09
Compare
Choose a tag to compare

copied from openapi-processor-core

OpenAPI 3.0 parser & JSON schema validation

openapi-processor provides another OpenAPI 3.0 parser. It includes JSON schema validation with detailed reporting.

To enable it, set the parser configuration to INTERNAL.

// build.gradle processor configuration

openapiProcessor {
    spring {
        processor 'io.openapiprocessor:openapi-processor-spring:2022.4'

        apiPath "${projectDir}/src/api/openapi.yaml"
        targetDir "$projectDir/build/openapi"
        mapping "${projectDir}/src/api/mapping.yaml"

        // use internal OpenAPI parser
        parser 'INTERNAL' 
    }
}

OpenAPI 3.1 (experimental)

The internal OpenAPI parser supports OpenAPI 3.1 but does not yet have schema validation.

To enable it, set the parser configuration to INTERNAL. It will automatically detect OpenAPI 3.0 & 3.1.

The processor does handle the renamed/changed OpenAPI 3.1 properties as needed for code generation:

type keyword

The type keyword allows a list of types. Defining a nullable type is done by adding "null" to the list of types.

# OpenAPI v3.0
type: string
nullable: true

# OpenAPI v3.1
type:
- "string"
- "null" 

The processor does support the new nullable definition. Apart from that it will use the first non-null type as the type for code generation.

exclusiveMinimum and exclusiveMaximum keywords

# OpenAPI v3.0
maximum: 42
exclusiveMaximum: true


# OpenAPI v3.1
exclusiveMaximum: 42

which is used for adding bean validations.

openapi-processor/openapi-processor-spring#141, missing import for javax.validation.constraints.Pattern

the imports for bean validation annotations were missing for item constraints of a mapped array. Having an api description like this

paths:
  /test:
    get:
      parameters:
        - in: query
          name: patternParam
          required: false
          description: query parameter with @Pattern annotation
          schema:
            $ref: '#/components/schemas/PatternParam'
      responses:
        '200':
          description: ok
  schemas:
    PatternParam:
      type: array
      items:
        type: string
        pattern: '.*'

and a mapping

openapi-processor-spring: v2

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

map:
  types:
  - type: array => java.util.List

did not generate the javax.validation.constraints.Pattern import.

package generated.api;

import annotation.Mapping;
import annotation.Parameter;
import java.util.List;
import javax.validation.constraints.Pattern;

public interface Api {

    @Mapping("/test")
    void getTest(@Parameter List<@Pattern(regexp = ".*") String> patternParam);

}

(ignore the @Mapping/@Parameter annotations, this is pseudo code used by the integration tests)

2022.4.1

23 Dec 10:08
Compare
Choose a tag to compare

copied from openapi-processor-core

restored small piece of accidentally deleted code

2022.4

23 Dec 10:07
Compare
Choose a tag to compare

copied from openapi-processor-core

openapi-processor/openapi-processor-core#92, processor does not handle empty schema

it is now possible (and necessary) to create a type mapping for an empty schema if the type is needed. Having an OpenAPI fragment like this

components:
  schemas:
    Empty: {}

the processor does not generate an Empty class (the schema has no object properties and it assumes that it is not necessary to create a model class for it) but the type Empty could still be referenced by another type (e.g. as property).

To avoid compilation errors it is necessary to add a type mapping for Empty:

openapi-processor-mapping: v2

options:
  package-name: generated

map:
  types:
    - type: Empty => java.lang.Object

openapi-processor/openapi-processor-core#91, model-name-suffix was not properly supported on generic parameters

having a type mapping with a generated generic parameter (i.e Foo in the example) in combination with model-name-suffix

openapi-processor-mapping: v2

options:
  package-name: generated
  model-name-suffix: Resource

map:
  types:
    - type: FooPage => org.springframework.data.domain.Page<{package-name}.model.Foo>

did ignore the model-name-suffix on the generic parameter and failed to generate the FooResource model.

2022.3

23 Dec 10:05
Compare
Choose a tag to compare

copied from openapi-processor-core

openapi-processor/openapi-processor-core#78, generate marker interface for oneOf objects

by enabling one-of-interface in the options

openapi-processor-mapping: v2

options:
  one-of-interface: true

the processor will create a marker interface for a oneOf of objects that is implemented by all objects in the oneOf list.

For an api like this:

paths:
  /foo:
    get:
      responses:
        '200':
          description: oneOf
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Foo'

components:
  schemas:

    Foo:
      type: object
      properties:
        foo:
          $ref: '#/components/schemas/FooOneOf'

    FooOneOf:
      oneOf:
        - $ref: '#/components/schemas/FooOne'
        - $ref: '#/components/schemas/FooTwo'

the processor generates the class Foo:

// simplified
public class Foo {
    private FooOneOf foo;
}

a marker interface:

public interface FooOneOf {}

and the two model class FooOne & FooTwo, that implement the marker interface:

// simplified
public class FooOne implements FooOneOf { /* ... */ }
// simplified
public class FooTwo implements FooOneOf { /* ... */ }

Without one-of-interface: true the processor does not generate a marker interface and the response class Foo uses Object as the type of the foo member.

// simplified Foo model class
public class Foo {
    private Object foo;
}

v2022.2

23 Dec 10:04
Compare
Choose a tag to compare

copied from openapi-processor-core

multi wrapper (e.g. Flux) with array type mapping failed

having a simple array response

application/json:
  schema:
    type: array
    items:
      $ref: '#/components/schemas/Foo'

with a common type mapping for array

openapi-processor-mapping: v2

options:
  package-name: generated

map:
  multi: reactor.core.publisher.Flux

  types:
    - type: array => java.util.List

caused a class cast exception.

openapi-processor/openapi-processor-core#86, merge allOf and sibling properties

having a schema like:

schema:
  type: object
  allOf:
    - type: object
      properties:
        foo:
          type: string
  properties:
    bar:
      type: string

did generate a model class without the properties of the root schema.

The processor will now create a model object with the properties of the root schema and all properties of the allOf schemas. In this case the merged model class will have a foo property and a bar property.

openapi-processor/openapi-processor-core#85, duplicate properties in allOf

having a schema like:

schema:
  allOf:
    - type: object
      properties:
        foo:
          type: string
    - type: object
      properties:
        foo:
          type: string

did generate an invalid model class with two foo properties.

The processor will now use only the last foo and it will only look at the name of the property.

2022.1

23 Dec 10:02
Compare
Choose a tag to compare

copied from openapi-processor-core

openapi-processor/openapi-processor-spring#136, readOnly/writeOnly

readOnly/writeOnly on object schema properties

Foo:
  type: object
  properties:
    barRead:
      readOnly: true
      allOf:
        - $ref: '#/components/schemas/Bar'
    barWrite:
      writeOnly: true
      allOf:
        - $ref: '#/components/schemas/Bar'

will translate to @JsonProperty annotations with read-only or write-only access:

public class Foo {

    @JsonProperty(value = "barRead", access = JsonProperty.Access.READ_ONLY)
    private Bar barRead;

    @JsonProperty(value = "barWrite", access = JsonProperty.Access.WRITE_ONLY)
    private Bar barWrite;

   // ....
}

openapi-processor/openapi-processor-core#82, @Email bean validation

In case bean validation is enabled a string schema with format email

schema:
  type: string
  format: email

will be annotated with @Email (javax.validation.constraints.Email)

2021.6

23 Dec 10:00
Compare
Choose a tag to compare

copied from openapi-processor-core

openapi-processor/openapi-processor-spring#133, improved error reporting

Sometimes parsing errors of the OpenAPI description were not be properly reported (e.g. by the maven plugin). Parsing/validation errors are now handled and reported at the processor level and reporting no longer depends on the plugin that calls the processor (gradle/maven).

openapi-processor/openapi-processor-spring#134, nested oneOf & anyOf

if an oneOf/anyOf was used in a schema property the processor generated code that used a non-existing class as java type for the property.

For example given the following OpenAPI description

openapi: 3.0.3
info:
  title: nested composed schema
  version: 1.0.0

paths:

  /foo-nested-one-of:
    get:
      responses:
        '200':
          description: nested oneOf
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FooNestedOneOf'


components:
  schemas:

    FooNestedOneOf:
      type: object
      properties:
        foo:
          oneOf:
          - $ref: '#/components/schemas/One'
          - $ref: '#/components/schemas/Two'
          - $ref: '#/components/schemas/Three'

the processor generated the pojo as:

 public class FooNestedOneOf {
 
     @JsonProperty("foo")
     private FooNestedOneOfFoo foo;
 
    public FooNestedOneOfFoo getFoo() {
         return foo;
     }
 
    public void setFoo(FooNestedOneOfFoo foo) {
         this.foo = foo;
     }
 
 }

where FooNestedOneOfFoo did not exist.

It is now using Object as type of ' foo` and generates:

public class FooNestedOneOf {

    @JsonProperty("foo")
    private Object foo;

    public Object getFoo() {
        return foo;
    }

    public void setFoo(Object foo) {
        this.foo = foo;
    }

}

dependency updates

updated swagger parser to 2.0.28 (was 2.0.27)