[FEATURE] [SPRING] Add support for custom beanValidation annotations
Created by: Mintas
Description
The feature is mostly inspired by https://bartko-mat.medium.com/openapi-generator-to-spring-boot-with-custom-java-validations-623381df9215
We want to be able to add our custom validation constraint annotations for java spring-based modules. Provide new vendor extension aka 'x-spring-constraint' and allow user-defined annotation class or package to be imported gracefully using configuration parameters (without any template customization).
This is extremely useful in combination with javax.validation.valueextraction.ValueExctractor , see https://javaee.github.io/javaee-spec/javadocs/javax/validation/valueextraction/package-summary.html
openapi-generator version
6.2.1 , current master
OpenAPI declaration file content or url
openapi: 3.0.3
info:
version: 1.0.0
description: Specification to show applicability of x-spring-constraint vendor extension
title: XSpringConstraintTest Api
paths:
/smth/add:
get:
parameters:
- in: query
name: quantity
schema:
type: integer
x-spring-constraint: "@Positive"
required: true
responses:
'200':
description: OK
content:
application/json:
schema:
type: boolean
/smth/remove:
get:
parameters:
- in: query
name: quantity
schema:
type: integer
x-spring-constraint: "@NotZero(message = \"custom\")"
responses:
'200':
description: OK
content:
application/json:
schema:
type: boolean
Plugin configuration:
generatorName = 'spring'
configOptions = [
dateLibrary: 'java8',
interfaceOnly: 'true',
openApiNullable: 'false',
java8: 'false',
customValidationAnnotationsPackage: 'org.custom.validation.annotations.*'
]
as alternative we can set this property to contains class name to be imported:
customValidationAnnotationsPackage: 'org.custom.validation.annotations.NotZero'
Generates:
package xyz.controller;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.multipart.MultipartFile;
import javax.validation.Valid;
import javax.validation.constraints.*;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import javax.annotation.Generated;
import org.custom.validations.*;
@Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2022-11-07T14:52:46.573574+03:00[Europe/Moscow]")
@Validated
@Tag(name = "smth", description = "the smth API")
public interface SmthApi {
default Optional<NativeWebRequest> getRequest() {
return Optional.empty();
}
/**
* GET /smth/add
*
* @param quantity (required)
* @return OK (status code 200)
*/
@Operation(operationId = "smthAddGet", responses = { @ApiResponse(responseCode = "200", description = "OK", content = { @Content(mediaType = "application/json", schema = @Schema(implementation = Boolean.class)) }) })
@RequestMapping(method = RequestMethod.GET, value = "/smth/add", produces = { "application/json" })
default ResponseEntity<Boolean> smthAddGet(@NotNull @Positive @Parameter(name = "quantity", description = "", required = true) @Valid @RequestParam(value = "quantity", required = true) Integer quantity) {
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
}
/**
* GET /smth/remove
*
* @param quantity (optional)
* @return OK (status code 200)
*/
@Operation(operationId = "smthRemoveGet", responses = { @ApiResponse(responseCode = "200", description = "OK", content = { @Content(mediaType = "application/json", schema = @Schema(implementation = Boolean.class)) }) })
@RequestMapping(method = RequestMethod.GET, value = "/smth/remove", produces = { "application/json" })
default ResponseEntity<Boolean> smthRemoveGet(@NotZero(message = "custom") @Parameter(name = "quantity", description = "") @Valid @RequestParam(value = "quantity", required = false) Integer quantity) {
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
}
}
Added with proposed feature:
//lines omitted
import org.custom.validations.*;
//lines omitted
default ResponseEntity<Boolean> smthAddGet(@NotNull @Positive/* other content omitted*/ Integer quantity) {
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
}
//lines omitted
default ResponseEntity<Boolean> smthRemoveGet(@NotZero(message = "custom") /* other content omitted*/ Integer quantity) {
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
}
}
Command line used for generation
Steps to reproduce
Related issues/PRs
Suggest a fix/enhancement
will propose a solution as PR from fork repository https://github.com/Mintas/openapi-generator