Releases: openapi-processor/openapi-processor-base
2023.2.1
#29 (fix), a property with a java keyword name generates invalid Java code
using a parameter/property name that was identical to a java keyword generated invalid Java code. For example, with a parameter and property name class
:
openapi: 3.0.3
info:
title: keyword identifier
version: 1.0.0
paths:
/keywords:
get:
parameters:
- name: class
description: parameter
in: query
schema:
$ref: '#/components/schemas/class'
responses:
'200':
description: the foo result
content:
application/json:
schema:
$ref: '#/components/schemas/class'
components:
schemas:
class:
type: object
properties:
class:
type: string
the processor did generate interfaces with an invalid class
parameter name and a model class with an invalid property name class
.
Now it adds a a
prefix if a parameter/property name is identical to any keyword:
package generated.api;
import annotation.Mapping;
import annotation.Parameter;
import generated.model.Class;
import generated.support.Generated;
@Generated(value = "openapi-processor-core", version = "test")
public interface Api {
@Mapping("/keywords")
Class getKeywords(@Parameter Class aClass);
}
package generated.model;
import com.fasterxml.jackson.annotation.JsonProperty;
import generated.support.Generated;
@Generated(value = "openapi-processor-core", version = "test")
public class Class {
@JsonProperty("class")
private String aClass;
public String getClass() {
return aClass;
}
public void setClass(String aClass) {
this.aClass = aClass;
}
}
#25 (fix), invalid type of enum parameter
an enum parameter name was not properly converted to valid class name. With a name foo-foo
openapi: 3.0.0
info:
title: sample API
version: 1.0.0
paths:
/foo:
get:
parameters:
- name: foo-foo
description: test parameter
in: query
schema:
type: string
enum:
- foo-1
responses:
'204':
description: response
the processor generated a class Foo-foo
instead of FooFoo
:
public interface Api {
@GetMapping(path = "/foo")
void getFoo(@RequestParam(name = "foo-foo", required = false) Foo-foo fooFoo);
}
#24 (fix), doesn't find nested schemas of additionalProperties
using {package-name}
with a nested schema of additionalProperties
did not find the nested schema.
this prevented mappings like
map:
types:
- type: Values => java.util.Map<java.lang.String, {package-name}.model.Value>>
- type: MultiValues => java.util.Map<java.lang.String, java.util.List<{package-name}.model.Value>>>
assuming Values
is nested schema of additionalProperties
:
components:
schemas:
Values:
description: key is string, value is a Value object
type: object
additionalProperties:
$ref: '#/components/schemas/Value'
2023.2
openapi-processor/openapi-processor-spring#150 (new), type mapping with nested generics
so far openapi-processor did allow only one level of generics. It is now possible to create type mappings with nested generics types.
openapi-processor-mapping: v2
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
openapi-processor/openapi-processor-spring#161 (new), annotation mapping allows class parameter
annotation mapping now accepts a java class type as parameter. It is now possible to add a mapping like this:
openapi-processor-mapping: v3
map:
types:
- type: string:foo @ io.oap.Annotation (value = io.oap.Bar.class)
openapi-processor/openapi-processor-spring#160 (fix), lost javadoc comment with type mapping
having a type mapping on the type of an object property did not write its description as javadoc comment as it does without mapping.
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.
dependency updates
- updated internal openapi-parser to 2023.2 (was 2023.1)
- updated swagger parser to 2.1.14 (was 2.0.28)
- update jackson to 2.15.1 (was 2.14.1)
2023.1.2
openapi-processor/openapi-processor-spring#157, bean validation support for mapped types broke additional parameters
the bean validation support on mapped types introduced in 2023.1 did not properly handle additional parameters.
openapi-processor/openapi-processor-spring#156, wrong bean-validation option in mapping json schema
the definition of the bean-validation
option in the mapping.yaml
expected string "true"/"false"
instead of boolean true
/false
.
2023.1.1
2023.1
#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
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
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 import
s 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
copied from openapi-processor-core
restored small piece of accidentally deleted code
2022.4
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
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 object
s 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;
}