From last section Spring Boot With OpenApi, we know how to set up and use basic features of OpenApi Generator for our Spring Boot project.
However, in some special cases, we will need do more than that like adding some custom annotations into specific generated classes or only on just some fields in them.
OpenApi supports us many way to achieve this one like using configuration in pom.xml, SUPPORTED VENDOR EXTENSIONS and  specification extensions or vendor extensions. Base on the business requirement then we can choose the most suitable one.
Below are SUPPORTED VENDOR EXTENSIONS that the OpenApi had supported.
Extension name
Description
Applicable for
Default value
x-discriminator-value
Used with model inheritance to specify value for discriminator that identifies current model
MODEL
x-implements
Ability to specify interfaces that model must implements
MODEL
empty array
x-setter-extra-annotation
Custom annotation that can be specified over java setter for specific field
FIELD
When field is array & uniqueItems, then this extension is used to add @JsonDeserialize(as = LinkedHashSet.class) over setter, otherwise no value
x-tags
Specify multiple swagger tags for operation
OPERATION
null
x-accepts
Specify custom value for 'Accept' header for operation
OPERATION
null
x-content-type
Specify custom value for 'Content-Type' header for operation
OPERATION
null
x-class-extra-annotation
List of custom annotations to be added to model
MODEL
null
x-field-extra-annotation
List of custom annotations to be added to property
FIELD
null
x-spring-paginated
Add org.springframework.data.domain.Pageable to controller method. Can be used to handle page & size query parameters
OPERATION
false
So While the OpenAPI specification tries to accommodate most use cases, additional data can be used to extend the specification and augment its functionality. These additional properties are known as specification extensions (previously called "vendor extensions"). The extension properties are implemented as patterned fields that start with the prefix x- naming convention such as x-custom-annotation. They can be used to describe extra functionality that is not covered by the standard OpenAPI Specification.
The specification extensions are grouped according to the element(s) of the OpenAPI specification that they extend. Specification extensions can only be used in the sections of your OpenAPI definition that support them - for example, you can't use an extension that modifies the info object inside the tag object.
Now, let's go through examples below then we can understand easier.
Usually, to protect our customer data from incoming requests which can contain invalid data or injection script, we usually create model classes for which contains validation like the format of field, the min length, the max length...etc.
So the OpenApi had supported this validation feature by enable useBeanValidationas true in the configOptions in pom.xml. See example below.
Note: By default the useBeanValidation is set as true by OpenApi. So we can skip setting it again in the configOptions.
<build><plugins><plugin><groupId>org.openapitools</groupId><artifactId>openapi-generator-maven-plugin</artifactId><version>6.0.0</version><executions><execution><goals><goal>generate</goal></goals><configuration><!-- path to the openapi file spec `.yml` --><inputSpec>${project.basedir}/src/main/resources/openapi/openapi-server.yml
</inputSpec><generatorName>spring</generatorName><!-- generated package for api interface --><apiPackage>com.springboot.cloud.openfeign.openapi.server.app.api</apiPackage><!-- generated package for models --><modelPackage>com.springboot.cloud.openfeign.openapi.server.app.model</modelPackage><!-- using supportingFilesToGenerate --><supportingFilesToGenerate>ApiUtil.java
</supportingFilesToGenerate><configOptions><delegatePattern>false</delegatePattern><dateLibrary>java8</dateLibrary><interfaceOnly>true</interfaceOnly><useBeanValidation>true</useBeanValidation><openApiNullable>true</openApiNullable></configOptions></configuration></execution></executions></plugin></plugins></build>
Now, let create the openapi-server.yml and add some validation as Min length, Max length as below.
openapi:3.0.3info:title:Swagger Openapi Serverdescription:'ThisistheOpenapiSpecificationForFeignServer'license:name:Apache 2.0url:http://www.apache.org/licenses/LICENSE-2.0.htmlversion:1.0.0tags:-name:serverdescription:all server apispaths:/v1/server/customers:post:tags:-serversummary:Create a customerdescription:create a customeroperationId:createCustomerrequestBody:description:request bodycontent:application/json:schema:$ref:'#/components/schemas/CustomerRequest'required:trueresponses:201:description:successful operationcontent:application/json:schema:type:stringformat:uuidget:tags:-serversummary:get customersdescription:get customersoperationId:getCustomersresponses:200:description:successful operationcontent:application/json:schema:type:arrayitems:$ref:'#/components/schemas/Customer'components:schemas:CustomerRequest:type:objectrequired:-emailproperties:fullName:type:stringexample:Nguyen Minh DucminLength:1maxLength:100email:type:stringformat:emailexample:ducnguyen@gmail.comaddress:type:stringexample:3/115 Binh Duongphone:type:stringexample:0999123445gender:type:stringenum:[M,F]dob:type:stringformat:dateCustomer:type:objectproperties:id:type:stringformat:uuidfullName:type:stringemail:type:stringformat:emailaddress:type:stringphone:type:stringgender:type:stringenum:[M,F]dob:type:stringformat:datecreatedAt:type:stringformat:date-timeupdatedAt:type:stringformat:date-time
Then let's build our source code and go to generated source, then you can see our fields have been added validation as below.
CustomerRequest.java
1 2 3 4 5 6 7 8 910111213141516
..../** * Get fullName * @return fullName */@Size(min=1,max=100)@Schema(name="fullName",example="Nguyen Minh Duc",required=false)publicStringgetFullName(){returnfullName;}publicvoidsetFullName(StringfullName){this.fullName=fullName;}....
Now, in case you want to add some custom annotations of lombok into your model classes, you can use the configOptions with properties additionalModelTypeAnnotations. In which In which you should define full path of your annotations. Ex: @lombok.Builder. See example below.
<build><plugins><plugin><groupId>org.openapitools</groupId><artifactId>openapi-generator-maven-plugin</artifactId><version>6.0.0</version><executions><execution><goals><goal>generate</goal></goals><configuration><!-- path to the openapi file spec `.yml` --><inputSpec>${project.basedir}/src/main/resources/openapi/openapi-server.yml
</inputSpec><generatorName>spring</generatorName><!-- generated package for api interface --><apiPackage>com.springboot.cloud.openfeign.openapi.server.app.api</apiPackage><!-- generated package for models --><modelPackage>com.springboot.cloud.openfeign.openapi.server.app.model</modelPackage><!-- using supportingFilesToGenerate --><supportingFilesToGenerate>ApiUtil.java
</supportingFilesToGenerate><configOptions><delegatePattern>false</delegatePattern><dateLibrary>java8</dateLibrary><interfaceOnly>true</interfaceOnly><useBeanValidation>true</useBeanValidation><openApiNullable>true</openApiNullable><additionalModelTypeAnnotations>@lombok.Builder
@lombok.NoArgsConstructor
@lombok.AllArgsConstructor
</additionalModelTypeAnnotations></configOptions></configuration></execution></executions></plugin></plugins></build>
Now, let's assume that you have some special annotations and you just want to apply them on some special models not on all models. In this case, you may want to use the supported vendor extesions of OpenApi.
For example we will add the annotation @lombok.Setter for only CustomerRequest model class and annotation @javax.validation.constraints.PastOrPresent for only field dob in Customer model class.
Let's use x-class-extra-annotation to add annotation for model CustomerRequest and the x-field-extra-annotation to add annotation for special field of Customer model in openapi-server.yml` as below.
openapi:3.0.3info:title:Swagger Openapi Serverdescription:'ThisistheOpenapiSpecificationForFeignServer'license:name:Apache 2.0url:http://www.apache.org/licenses/LICENSE-2.0.htmlversion:1.0.0tags:-name:serverdescription:all server apispaths:/v1/server/customers:post:tags:-serversummary:Create a customerdescription:create a customeroperationId:createCustomerrequestBody:description:request bodycontent:application/json:schema:$ref:'#/components/schemas/CustomerRequest'required:trueresponses:201:description:successful operationcontent:application/json:schema:type:stringformat:uuidget:tags:-serversummary:get customersdescription:get customersoperationId:getCustomersresponses:200:description:successful operationcontent:application/json:schema:type:arrayitems:$ref:'#/components/schemas/Customer'components:schemas:CustomerRequest:type:objectx-class-extra-annotation:"@lombok.Setter"required:-emailproperties:fullName:type:stringexample:Nguyen Minh DucminLength:1maxLength:100email:type:stringformat:emailexample:ducnguyen@gmail.comaddress:type:stringexample:3/115 Binh Duongphone:type:stringexample:0999123445gender:type:stringenum:[M,F]dob:type:stringformat:dateCustomer:type:objectproperties:id:type:stringformat:uuidfullName:type:stringemail:type:stringformat:emailaddress:type:stringphone:type:stringgender:type:stringenum:[M,F]dob:type:stringformat:datex-field-extra-annotation:"@javax.validation.constraints.PastOrPresent"createdAt:type:stringformat:date-timeupdatedAt:type:stringformat:date-time
Now, let's build our source code and go to generated source.
Then you can see in the CustomerRequest model you will see there is annotation @lombok.Setter above the class. But you will not see it on Customer model class.
Then let's continue to check the Customer model class, you will see the special annotation PastOrPresent for field dob as below. But you will not see it in the CustomerRequest model class.
As you can see in the example above, we can add specific annotations for classes and fields that we want. However, every time we add an annotation we have to put full path of it and what happens if we have to add multiple annotations on a specific field or a specific class?
If we use the Supported Vendor Extension above, we can do it in the openapi-server.yml like below.
openapi:3.0.3info:title:Swagger Openapi Serverdescription:'ThisistheOpenapiSpecificationForFeignServer'license:name:Apache 2.0url:http://www.apache.org/licenses/LICENSE-2.0.htmlversion:1.0.0tags:-name:serverdescription:all server apispaths:/v1/server/customers:post:tags:-serversummary:Create a customerdescription:create a customeroperationId:createCustomerrequestBody:description:request bodycontent:application/json:schema:$ref:'#/components/schemas/CustomerRequest'required:trueresponses:201:description:successful operationcontent:application/json:schema:type:stringformat:uuidget:tags:-serversummary:get customersdescription:get customersoperationId:getCustomersresponses:200:description:successful operationcontent:application/json:schema:type:arrayitems:$ref:'#/components/schemas/Customer'components:schemas:CustomerRequest:type:objectx-class-extra-annotation:"@lombok.Setter/n@lombok.Getter"required:-emailproperties:fullName:type:stringexample:Nguyen Minh DucminLength:1maxLength:100email:type:stringformat:emailexample:ducnguyen@gmail.comaddress:type:stringexample:3/115 Binh Duongphone:type:stringexample:0999123445gender:type:stringenum:[M,F]dob:type:stringformat:dateCustomer:type:objectproperties:id:type:stringformat:uuidfullName:type:stringemail:type:stringformat:emailaddress:type:stringphone:type:stringgender:type:stringenum:[M,F]dob:type:stringformat:datex-field-extra-annotation:"@javax.validation.constraints.PastOrPresent/n@javax.validation.constraints.Size(min=3,max=20)"createdAt:type:stringformat:date-timeupdatedAt:type:stringformat:date-time
As you can see, we have to put full path of annotation and for multiple annotation we have to put space or "/n". It is bad for developer to write and for people who read this OpenApi specification. Moreover, when the models are generated, so also see annotation with full path, so it is not nice, we would like to see the imports on the top of the generated class and only annotations on classes or fields.
So, using Vendor Extension will help us to solve this issue.
Because in this example, we use annotations of javax validator so to make sure this library is not imported by default and we are controlling imports for annotations so we will disable useBeanValidation and we also need to add templateDirectory for using custom OpenApi templates.
<build><plugins><plugin><groupId>org.openapitools</groupId><artifactId>openapi-generator-maven-plugin</artifactId><version>6.0.0</version><executions><execution><goals><goal>generate</goal></goals><configuration><!-- path to the openapi file spec `.yml` --><inputSpec>${project.basedir}/src/main/resources/openapi/openapi-server.yml
</inputSpec><generatorName>spring</generatorName><!-- generated package for api interface --><apiPackage>com.springboot.cloud.openfeign.openapi.server.app.api</apiPackage><!-- generated package for models --><modelPackage>com.springboot.cloud.openfeign.openapi.server.app.model</modelPackage><!-- using supportingFilesToGenerate --><supportingFilesToGenerate>ApiUtil.java
</supportingFilesToGenerate><!-- using templateDirectory custom templates for openapi generator --><templateDirectory>${project.basedir}/src/main/resources/templates/java-spring</templateDirectory><configOptions><delegatePattern>false</delegatePattern><dateLibrary>java8</dateLibrary><interfaceOnly>true</interfaceOnly><useBeanValidation>false</useBeanValidation><additionalModelTypeAnnotations>@lombok.Builder
@lombok.NoArgsConstructor
@lombok.AllArgsConstructor
</additionalModelTypeAnnotations><openApiNullable>false</openApiNullable></configOptions></configuration></execution></executions></plugin></plugins></build>
Then, we can go to this github repo to download full templates of OpenApi generator of JavaSpring and put it into our resources folder.
Then we can create a custom vendor extension x-internal-imports for list of imports library by adding the mustache script below into the model.mustache.
- Then for using list of annotations on specific classes and fields, we can go to pojo.mustache file and edit the {{{vendorExtensions.x-class-extra-annotation}}} and {{{vendorExtensions.x-field-extra-annotation}}}to {{{.}}} as below.
Finally, let's go to OpenApi specification openapi-server.yml and you can use custom vendor extension x-internal-imports to create a list of import library for your specific model. For x-class-extra-annotation and x-field-extra-annotation you can use single or list of annotations.
So, we had the list of imports, annotations for classes and fields as we defined for the CustomerRequest in the openapi-server.yml and you will not see them in the Customer model.