Skip to content

Releases: openapi-processor/openapi-processor-base

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)

2021.5.1

23 Dec 09:59
Compare
Choose a tag to compare

copied from openapi-processor-core

openapi-processor/openapi-processor-spring#132, fixed missing bean validation on request body

the processor did not always generate proper bean validation annotations on a parameter/request body. In the example below the @Size() annotation was missing on the request body array with size constraints:

openapi-processor-mapping: v2

options:
  # ...
  bean-validation: true

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

  requestBody:
    content:
      application/json:
        schema:
          type: array
          items:
            type: string
            minLength: 2
            maxLength: 2

  ...
public interface Api {

    @PostMapping(path = "/foo", consumes = {"application/json"})
    void postFoo(@RequestBody(required = false) List<@Size(min = 2, max = 2) String> body);

}

This fix includes a general change in the annotation order. The bean validation annotation moved nearer to the parameter type behind the mapping annotations. (Note that @Parameter is just a placeholder for the Spring/Micronaut mapping annotations)

before

    @Mapping("/items")
    void getItems(
            @Size(min = 2) @Parameter String[] min,
            @Size(max = 4) @Parameter String[] max,
            @Size(min = 2, max = 4) @Parameter String[] minMax);

after

    @Mapping("/items")
    void getItems(
            @Parameter @Size(min = 2) String[] min,
            @Parameter @Size(max = 4) String[] max,
            @Parameter @Size(min = 2, max = 4) String[] minMax);

2021.5

23 Dec 09:57
Compare
Choose a tag to compare

copied from openapi-processor-core

openapi-processor/openapi-processor-core#68, improved response type handling

this is a breaking change because it changes the code that gets generated by default. To keep the old behavior set result-style in the mapping.yaml to all. See the example below.

old behavior

currently if an endpoint returns multiple types, a success response (typically 200 ok) and at least one error response, the processor generates endpoint methods with an Object return value (or if generic something like ResponseType<?>) to handle the (usually) type wise unrelated ok and error responses.

For example, the following endpoint:

paths:
  /foo:
    get:
      responses:
        '200':
          description: json or plain text result
          content:
            application/json:
                schema:
                  $ref: '#/components/schemas/Foo'
            text/plain:
                schema:
                  type: string
        default:
          description: error
          content:
            application/xml:
                schema:
                  $ref: '#/components/schemas/Error'

will produce this java interface:

public interface Api {

    @Mapping("/foo")
    Object getFooApplicationJson();

    @Mapping("/foo")
    Object getFooTextPlain();

}

It generates a method for each success response with an Object response because the error and the success response (usually) do not have the same type as the error response.

Object is not a very useful result type because the compiler can't check if whatever we return in the implementation matches the openapi response type.

new behavior

Since it is common practice to handle errors by throwing exceptions (e.g. in combination with the Spring @ResponseStatus to provide the http response code) the endpoint methods don't need to return different types and it is possible to simply use the type of the success response.

With this release the processor will, by default, generate the endpoint methods with specific return types:

public interface Api {

    @Mapping("/foo")
    Foo getFooApplicationJson();

    @Mapping("/foo")
    String getFooTextPlain();

}

configuration

To switch between old and new behavior there is a new mapping configuration to control the style of the return type named result-style. It has two possible values: success or all. This is currently a global switch.

The default is success, i.e. the processor will automatically generate the code using the new behavior. In case the old behavior is required set the result-style to all.

openapi-processor-mapping: v2

options:
  package-name: ...

map:
  #result-style: success  # use the success result type, this is the default
  result-style: all # use an Object return type

2021.4.2

23 Dec 09:54
Compare
Choose a tag to compare

copied from openapi-processor-core

openapi-processor/openapi-processor-core#72, missing @NotNull bean-validation with allOf composition

fixed missing required constraints of the composed object of an allOf schema list. The required constraints of the source schemas were ignored causing the missing @NotNull annotation.

the fix is based on a pull request by @Tucos

2021.4.1

23 Dec 09:53
Compare
Choose a tag to compare

copied from openapi-processor-core

openapi-processor/openapi-processor-spring#128, broken import list for allOf schema

fixed the imports list of a composed allOf schema. The processor did not properly walk the property tree of the merged schema and it generated a model class with missing imports.

2021.4

23 Dec 09:51
Compare
Choose a tag to compare

copied from openapi-processor-core

openapi-processor/openapi-processor-core#62, validate mapping with mapping json schema

Sometimes the processor generates wrong or unexpected code that seems to ignore a setting from the mapping.yaml. Usually this is caused by an error in the mapping.yaml, e.g. because of a wrong indentation.

To ease the pain of finding the error in the mapping.yaml it is validated with the mapping json schema. The validation step provides warnings only, i.e. the processor will still run.

#63, support pattern constraint

The OpenAPI pattern constraint translates to a @Pattern bean validation annotation. For example a parameter like this

# OpenAPI
...
parameters:
  - in: query
     name: anything
     schema:
       type: string
       pattern: .*\.\\
       description: string with regex constraint

will add a corresponding @Pattern(...) annotation to the method parameter:

// java
import javax.validation.constraints.Pattern;

  ...
  void getWithPattern(@Pattern(".*\\.\\\\") ... String ...);

openapi-processor/openapi-processor-core#64, add @Valid annotation on collections

Collections with object items are annotated with @Valid annotation to enable validation of the items in the collection.

Like this for array:

// java
public class Foo {

    @Valid
    ...
    private Bar[] bars;
    ...
}

or like this for Collection, Set or List:

// java
public class Foo {
    ...
    private Collection<@Valid Bar> bars;
    ...
}

openapi-processor/openapi-processor-core#65, automatically add a suffix to generated model pojos and enums

it is now possible to configure a suffix that the processor will automatically append to the name of model pojo classes and enum classes.

# mapping.yaml
openapi-processor-mapping: v2

options:
  package-name: io.openapiprocessor
  model-name-suffix: Resource  # or Dto or ....

The model-name-suffix option is optional (string value, by default it is empty (i.e. it is disabled)).

The suffix helps to

  • avoid duplicate class names in generated code and normal code
  • makes it easier to recognize which role or in which context a class is used. Is it a data transfer class or is it a domain class?
  • keeps the suffix "noise" out of the OpenAPI description

If a schema name from the OpenAPI description already ends with the model-name-suffix, the processor will not append the suffix. This allows to migrate an existing api with a suffix in the API to model-name-suffix step by step.

Applying the above mapping to the following api

# OpenAPI 
paths:
  /foo:
    get:
      responses:
        '200':
          description: the foo result
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Foo' # <1>

components:
  schemas:

    Foo:
      type: object
      properties:
        nested:
          $ref: '#/components/schemas/BarResource' # <1>

    BarResource:
      type: object
      properties:
        prop:
          type: string

will create the classes

// java

// interface
public interface Api {

    @Mapping("/foo")
    FooResource getFoo(); // <2>

}

// pojos
public class FooResource { // <2>

    // ...

    @JsonProperty("nested")
    private BarResource nested;

    // ...
}

public class BarResource { // <3>

    // ...
}
  • <1> a schema name without suffix
  • <2> the class name of the Foo schema got the configured Resource suffix
  • <3> the class name of the BarResource is identical to the original schema name. Since the existing suffix is equal to model-name-suffix it is ignored. Otherwise, This prevents funny class names like BarResourceResource.

openapi-processor/openapi-processor-core#66, parameters in javadoc were not written as java identifiers

the original parameter name from the OpenAPI description was used to create the javadoc @param comment which could be an invalid java identifier (e.g. foo-bar).

/**
 ...
 * @param foo-bar a foo bar 
 */

The javadoc is now generated with the same valid java identifier used in the source code:

/**
 ...
 * @param fooBar a foo bar 
 */

extract multi-part encoding

the parsing step extracts the encoding/contentType of a multipart content. This allows a processor to consider the encoding content type when selecting the annotation for the part.

openapi-processor-spring uses this to select between @RequestPart and @RequestParam. If an econding/contentType is available it will use @RequestPart, if no econding/contentType is available it will use @RequestParam.

openapi: 3.0.2
info:
  title: params-request-body-multipart
  version: 1.0.0

paths:
  /multipart:
    post:
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                file:
                  type: string
                  format: binary
                json:
                  type: object
                  properties:
                    foo:
                      type: string
                    bar:
                      type: string
            encoding:
              file:
                contentType: application/octet-stream
              json:
                contentType: application/json          
      responses:
        '204':
          description: empty

openapi-processor/openapi-processor-core#67, pojos only used in a multipart response are not generated

improved detection of used schemas for model class generation. It now properly detects schemas that are only use by a multipart response.

Since the "parts" are conerted into single parameters, there is no need for a request body pojo that contains all parts. Filtering the all parts pojo did drop the single part pojos.

method level exclude did override endpoint level exclude

If the mapping.yaml did have a method level endpoint mapping with exclude: false (the default if not set) it did override the exclude: true at the endpoint level.

# mapping.yaml
map:
  paths:
    /endpoint:
      exclude: true

      get:
        ...

openapi-processor/openapi-processor-core#59, operationId did override method names with media types

for example, having the following response

paths:
  /foo:
    get:
      # operationId: get_foo_operation
      responses:
        '200':
          description: json or plain text result
          content:
            application/json:
                schema:
                  $ref: '#/components/schemas/Foo'
            text/plain:
                schema:
                  type: string

the processor generated

    @Mapping("/foo")
    Foo getFooOperation();

    @Mapping("/foo")
    String getFooOperation();

instead of

    @Mapping("/foo")
    Foo getFooOperationApplicationJson();

    @Mapping("/foo")
    String getFooOperationTextPlain();

dependency updates

updated swagger parser to 2.0.26 (was 2.0.25)

2021.3.1

23 Dec 09:48
Compare
Choose a tag to compare

copied from openapi-processor-core

openapi-processor/openapi-processor-spring#126

fixed duplicate media types in the produces parameter of the mapping annotation.

dependency updates

updated swagger parser to 2.0.25 (was 2.0.24)

2021.3

23 Dec 09:46
Compare
Choose a tag to compare

copied from openapi-processor-core

javadoc improvements

openapi-processor/openapi-processor-core#56, generate endpoint javadoc of an OpenAPI operation from summary & description (previously only description was used) using the following format:

/**
 * OpenAPI summary (plain text)
 * 
 * OpenAPI description (common mark)
 */
@GetMapping("/foo")
Foo getFoo();

#openapi-processor/openapi-processor-core57, generate pojo javadoc from description fields.

/** schema description (common mark) */
public class Foo {

    /** property description (common mark) */
    @JsonProperty("foobar")
    private String foobar;

    public String getFoobar() {
        return foobar;
    }

    public void setFoobar(String foobar) {
        this.foobar = foobar;
    }

}

The processor generates multi line javadoc comments but the code formatter may flatten them into single line comments as in the example above.

openapi-processor/openapi-processor-spring#124, $ref-chain

A $ref-chain, like the one below, (a $ref that points to another $ref and so on..., possibly spanning multiple files) lost the original/correct name of the schema and generated wrong class names. The processor does now properly resolve the chain with the correct name.

As an example for the chain below, the processor selects User for the User schema (correct). Previously it selected user or something else depending on the chain (wrong):

openapi.yaml (excerpt):

paths:
  '/user':
    $ref: ./apis/user.v1.yaml#/paths/~1user

apis/user.v1.yaml (excerpt):

paths:
  '/user':
    post:
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'

components:
  schemas:
    User:
      $ref: ../models/user.model.v1.yaml

models/user.model.v1.yaml (excerpt):

type: object
properties:
  ...

improved names of inline schemas (maybe breaking)

internally the processor assigns names to inline schemas (request body & response). For example the following response would get the name QueryResponse200. It is now QueryGetResponse200. Difference is that it contains the http method.

...
paths:
  /query:
    get:
      responses:
        '200':
           ...

In theory it is possible to map the schema using its generated inline name (named schema mappings are preferred). Since the inline name has changed such a mapping needs to be updated.

updated dependencies

  • updated openapi4j parser to 1.0.7 (was 1.0.4)