object annotation mapping & lombok
27. July 2023
With openapi-processor-spring/micronaut release 2023.3 openapi-processor has a new mapping feature that allows it to add annotations to all generated model classes with a single mapping entry.
This is very useful in combination with lombok.
The article is based on the openapi-processor sample samples:spring-mvc-boot-3-lombok. The sample has a few more mapping entries.
the api
here is the sample api. Nothing clever, it is just for demonstration. :-)
It has a simple post
endpoints that accepts a Foo
schema. Foo
has a few properties one of them a Bar
schema.
openapi: 3.1.0
info:
title: openapi-processor-spring sample api
version: 1.0.0
paths:
/foo:
post:
tags:
- foo
summary: echo a Foo.
description: simple sample endpoint
requestBody:
$ref: '#/components/requestBodies/FooBody'
responses:
'200':
description: foo
content:
application/json:
schema:
$ref: '#/components/schemas/Foo'
components:
schemas:
Foo:
type: object
properties:
foo:
type: string
maxLength: 10
id:
type: string
format: uuid
bar:
$ref: '#/components/schemas/Bar'
Bar:
type: object
properties:
bar:
type: string
maxLength: 20
requestBodies:
FooBody:
content:
application/json:
schema:
$ref: '#/components/schemas/Foo'
no mapping
Without (annotation) mappings the configuration (mapping.yaml
) is very simple:
mapping.yaml
openapi-processor-mapping: v4
options:
package-name: io.openapiprocessor.openapi
bean-validation: jakarta
format-code: false
javadoc: true
openapi-processor(-spring) will generate an interface for the endpoint and two standard pojo classes for the schemas Foo
and Bar
.
Here is the generated interface:
FooApi.java
interfacepackage io.openapiprocessor.openapi.api;
import io.openapiprocessor.openapi.model.Foo;
import io.openapiprocessor.openapi.support.Generated;
import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@Generated(value = "openapi-processor-spring", version = "2023.3")
public interface FooApi {
/**
* echo a Foo.
*
* simple sample endpoint
*
* @return foo
*/
@PostMapping(path = "/foo", consumes = {"application/json"}, produces = {"application/json"})
Foo postFoo(@RequestBody(required = false) @Valid Foo body);
}
and the pojo model classes:
Foo.java
pojopackage io.openapiprocessor.openapi.model;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.openapiprocessor.openapi.support.Generated;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Size;
@Generated(value = "openapi-processor-spring", version = "2023.3")
public class Foo {
@Size(max = 10)
@JsonProperty("foo")
private String foo;
@JsonProperty("id")
private String id;
@Valid
@JsonProperty("bar")
private Bar bar;
// getter and setter
}
Bar.java
is similar with different properties.
lombok
The generated classes doesn’t implement anything apart the getter and setters. No equals()
, hashCode()
or anything else.
openapi-processor does minimize the generated logic which would never really fit anyway.
If you need equals()
, hashCode()
or a Builder
to make the model classes easier to use you can do that with lombok and the new object annotation mapping.
lombok object mapping
The object annotation mapping tells the processor to annotate all object
s (i.e. all generated model classes) with the given annotation.
With annotation mapping the configuration has a few new lines:
mapping.yaml
openapi-processor-mapping: v4
options:
package-name: io.openapiprocessor.openapi
bean-validation: jakarta
format-code: false
javadoc: true
map:
types:
# annotates all generated model classes
- type: object @ lombok.Builder (1)
- type: object @ lombok.EqualsAndHashCode (2)
1 | adds the lombok Builder annotation to all object s |
2 | adds the lombok EqualsAndHashCode annotation to all object s |
Note that the annotation is given with package. The processor requires it to generate the import
statements.
With the changes the generated model classes will now look like this:
Foo
pojo with lombokpackage io.openapiprocessor.openapi.model;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.openapiprocessor.openapi.support.Generated;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Size;
import lombok.Builder;
import lombok.EqualsAndHashCode;
@Builder (1)
@EqualsAndHashCode (1)
@Generated(value = "openapi-processor-spring", version = "2023.3")
public class Foo {
@Size(max = 10)
@JsonProperty("foo")
private String foo;
@JsonProperty("id")
private String id;
@Valid
@JsonProperty("bar")
private Bar bar;
// getter and setter
}
Bar
pojo with lombokpackage io.openapiprocessor.openapi.model;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.openapiprocessor.openapi.support.Generated;
import jakarta.validation.constraints.Size;
import lombok.Builder;
import lombok.EqualsAndHashCode;
@Builder (1)
@EqualsAndHashCode (1)
@Generated(value = "openapi-processor-spring", version = "2023.3")
public class Bar {
@Size(max = 20)
@JsonProperty("bar")
private String bar;
// getter and setter
}
1 | the additional lombok annotations at the class level. |
Now we can use the lombok builder and equals()
/ hashcode()
with the model classes generated from the OpenAPI description.
Nice!
limitations?
This is a new feature, and we have to find out where it is useful and where not.
known limitations:
-
an
object
annotation will always add the given annotation at the class level of the generated class.
lombok specific:
-
the processor generates getters and setter itself, so the lombok
@Getter
and@Setter
annotation can’t be used.
object mapping with parameters
The mapping will accept (simple) annotation parameters.
For example if you don’t like lombok’s default builder name, just add its annotation parameter to change it. Order of parameters or whitespaces do not matter.
openapi-processor-mapping: v4
options:
package-name: io.openapiprocessor.openapi
bean-validation: jakarta
format-code: false
javadoc: true
map:
types:
- type: object @ lombok.Builder(builderMethodName = "factory")
summary
This article shows how we can use an object
annotation mapping to improve the model classes generated from the OpenAPI description with lomboks @Builder
and @EqualsAndHashCode
annotations.
To learn more about openapi-processor and how to generate controller interfaces and model classes from an OpenAPI description take a look at the documentation.