From 7f97bc1b983d3c0f6e6c029336519c81d16f547f Mon Sep 17 00:00:00 2001 From: ioanadinuit <83220826+ioanadinuit@users.noreply.github.com> Date: Thu, 11 Nov 2021 20:22:13 +0200 Subject: [PATCH] BAEL-5080 (#11436) * BAEL-5080 Custom validation with Swagger Codegen Add tutorial code * BAEL-5080 Custom validation with Swagger Codegen Formatting * BAEL-5080 Custom validation with Swagger Codegen Swagger doc update * remove Licence file --- .../README.md | 1 + .../pom.xml | 103 ++++++++++++ .../openapi/petstore/PetstoreApplication.java | 13 ++ .../petstore/controller/PetController.java | 17 ++ .../controller/PetControllerAdvice.java | 20 +++ .../petstore/validation/Camelcase.java | 22 +++ .../validation/CamelcaseValidator.java | 35 ++++ .../src/main/resources/application.properties | 1 + .../resources/openapi/templates/api.mustache | 150 ++++++++++++++++++ .../templates/beanValidationCore.mustache | 26 +++ .../openapi/templates/cookieParams.mustache | 1 + .../resources/openapi/templates/enum.mustache | 31 ++++ .../openapi/templates/model.mustache | 42 +++++ .../openapi/templates/modelEnum.mustache | 68 ++++++++ .../src/main/resources/petstore.yml | 65 ++++++++ 15 files changed, 595 insertions(+) create mode 100644 spring-swagger-codegen/custom-validations-opeanpi-codegen/README.md create mode 100644 spring-swagger-codegen/custom-validations-opeanpi-codegen/pom.xml create mode 100644 spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/java/com/baeldung/openapi/petstore/PetstoreApplication.java create mode 100644 spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/java/com/baeldung/openapi/petstore/controller/PetController.java create mode 100644 spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/java/com/baeldung/openapi/petstore/controller/PetControllerAdvice.java create mode 100644 spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/java/com/baeldung/openapi/petstore/validation/Camelcase.java create mode 100644 spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/java/com/baeldung/openapi/petstore/validation/CamelcaseValidator.java create mode 100644 spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/application.properties create mode 100644 spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/api.mustache create mode 100644 spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/beanValidationCore.mustache create mode 100644 spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/cookieParams.mustache create mode 100644 spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/enum.mustache create mode 100644 spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/model.mustache create mode 100644 spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/modelEnum.mustache create mode 100644 spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/petstore.yml diff --git a/spring-swagger-codegen/custom-validations-opeanpi-codegen/README.md b/spring-swagger-codegen/custom-validations-opeanpi-codegen/README.md new file mode 100644 index 0000000000..83eec25c03 --- /dev/null +++ b/spring-swagger-codegen/custom-validations-opeanpi-codegen/README.md @@ -0,0 +1 @@ +# This is a sample on how we can merge the OpenApi code generation with the a custom annotation using ConstraintValidator diff --git a/spring-swagger-codegen/custom-validations-opeanpi-codegen/pom.xml b/spring-swagger-codegen/custom-validations-opeanpi-codegen/pom.xml new file mode 100644 index 0000000000..53e5006bf4 --- /dev/null +++ b/spring-swagger-codegen/custom-validations-opeanpi-codegen/pom.xml @@ -0,0 +1,103 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.5.4 + + + com.example + petstore + 0.0.1-SNAPSHOT + petstore + Demo project for Swagger Custom Validations Codegen + + 11 + 3.0.0 + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.hibernate + hibernate-validator + 6.0.10.Final + + + javax.validation + validation-api + 2.0.1.Final + + + org.openapitools + openapi-generator + 3.3.4 + + + io.springfox + springfox-oas + ${springfox-version} + + + io.springfox + springfox-swagger-ui + ${springfox-version} + + + com.fasterxml.jackson.core + jackson-databind + 2.10.0.pr3 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + org.openapitools + openapi-generator-maven-plugin + 5.1.0 + + + + generate + + + + ${project.basedir}/src/main/resources/petstore.yml + + spring + com.baeldung.openapi.api + com.baeldung.openapi.model + + ApiUtil.java + + + false + java8-localdatetime + + + src/main/resources/openapi/templates + + + + + + + + + + diff --git a/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/java/com/baeldung/openapi/petstore/PetstoreApplication.java b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/java/com/baeldung/openapi/petstore/PetstoreApplication.java new file mode 100644 index 0000000000..5a6372ba22 --- /dev/null +++ b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/java/com/baeldung/openapi/petstore/PetstoreApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.openapi.petstore; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class PetstoreApplication { + + public static void main(String[] args) { + SpringApplication.run(PetstoreApplication.class, args); + } + +} diff --git a/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/java/com/baeldung/openapi/petstore/controller/PetController.java b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/java/com/baeldung/openapi/petstore/controller/PetController.java new file mode 100644 index 0000000000..081d0cb6f9 --- /dev/null +++ b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/java/com/baeldung/openapi/petstore/controller/PetController.java @@ -0,0 +1,17 @@ +package com.baeldung.openapi.petstore.controller; + +import com.baeldung.openapi.api.PetsApi; +import com.baeldung.openapi.model.Pet; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; + +import java.util.Arrays; +import java.util.List; + +@Controller +public class PetController implements PetsApi { + + public ResponseEntity> findPetsByName(String name) { + return ResponseEntity.ok(Arrays.asList(new Pet().id(1L).name(name))); + } +} diff --git a/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/java/com/baeldung/openapi/petstore/controller/PetControllerAdvice.java b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/java/com/baeldung/openapi/petstore/controller/PetControllerAdvice.java new file mode 100644 index 0000000000..cf243dbb46 --- /dev/null +++ b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/java/com/baeldung/openapi/petstore/controller/PetControllerAdvice.java @@ -0,0 +1,20 @@ +package com.baeldung.openapi.petstore.controller; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; + +import javax.validation.ConstraintViolationException; + +@ControllerAdvice +public class PetControllerAdvice { + + @ResponseBody + @ResponseStatus(HttpStatus.BAD_REQUEST) + @ExceptionHandler(ConstraintViolationException.class) + public void handleConstraintViolationException() { + + } +} diff --git a/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/java/com/baeldung/openapi/petstore/validation/Camelcase.java b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/java/com/baeldung/openapi/petstore/validation/Camelcase.java new file mode 100644 index 0000000000..b0b0b739e2 --- /dev/null +++ b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/java/com/baeldung/openapi/petstore/validation/Camelcase.java @@ -0,0 +1,22 @@ +package com.baeldung.openapi.petstore.validation; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.*; + +@Documented +@Constraint(validatedBy = {CamelcaseValidator.class}) +@Target({ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface Camelcase { + + String message() default "Name should be uppercase."; + + boolean required() default true; + + Class[] groups() default {}; + + Class[] payload() default {}; + + String[] values() default {}; +} \ No newline at end of file diff --git a/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/java/com/baeldung/openapi/petstore/validation/CamelcaseValidator.java b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/java/com/baeldung/openapi/petstore/validation/CamelcaseValidator.java new file mode 100644 index 0000000000..2b08e3dd2a --- /dev/null +++ b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/java/com/baeldung/openapi/petstore/validation/CamelcaseValidator.java @@ -0,0 +1,35 @@ +package com.baeldung.openapi.petstore.validation; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import java.util.Objects; + +public class CamelcaseValidator implements ConstraintValidator { + + private Camelcase uppercaseAnnotation; + + public void initialize(Camelcase constraintAnnotation) { + this.uppercaseAnnotation = constraintAnnotation; + } + + @Override + public boolean isValid(String nameField, ConstraintValidatorContext context) { + String correctName = buildCorrectName(nameField); + if (uppercaseAnnotation.required() + && (Objects.isNull(nameField) || nameField.isBlank() + || !correctName.equals(nameField))) { + context = context + .buildConstraintViolationWithTemplate(this.uppercaseAnnotation.message()) + .addConstraintViolation(); + context.disableDefaultConstraintViolation(); + return false; + } + return true; + } + + private String buildCorrectName(String nameField) { + String upCase = String.valueOf(nameField.charAt(0)).toUpperCase(); + String lowCase = nameField.substring(1).toLowerCase(); + return upCase.concat(lowCase); + } +} \ No newline at end of file diff --git a/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/application.properties b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/application.properties new file mode 100644 index 0000000000..d5e4d42eb8 --- /dev/null +++ b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/application.properties @@ -0,0 +1 @@ +openapi.petStore.base-path=/ diff --git a/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/api.mustache b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/api.mustache new file mode 100644 index 0000000000..a7a35d43b5 --- /dev/null +++ b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/api.mustache @@ -0,0 +1,150 @@ +/** + * NOTE: This class is auto generated by OpenAPI Generator (https://com.baeldung.openapi-generator.tech) ({{{generatorVersion}}}). + * https://com.baeldung.openapi-generator.tech + * Do not edit the class manually. + */ +package {{package}}; + +{{#imports}}import {{import}}; +{{/imports}} +import io.swagger.annotations.*; +import com.baeldung.openapi.petstore.validation.Camelcase; +{{#jdk8-no-delegate}} +{{#virtualService}} +import io.virtualan.annotation.ApiVirtual; +import io.virtualan.annotation.VirtualService; +{{/virtualService}} +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +{{/jdk8-no-delegate}} +import org.springframework.http.ResponseEntity; +{{#useBeanValidation}} +import org.springframework.validation.annotation.Validated; +{{/useBeanValidation}} +{{#vendorExtensions.x-spring-paginated}} +import org.springframework.data.domain.Pageable; +{{/vendorExtensions.x-spring-paginated}} +import org.springframework.web.bind.annotation.*; +{{#jdk8-no-delegate}} + {{^reactive}} +import org.springframework.web.context.request.NativeWebRequest; + {{/reactive}} +{{/jdk8-no-delegate}} +import org.springframework.web.multipart.MultipartFile; +{{#reactive}} +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import org.springframework.http.codec.multipart.Part; +{{/reactive}} +import springfox.documentation.annotations.ApiIgnore; + +{{#useBeanValidation}} +import javax.validation.Valid; +import javax.validation.constraints.*; +{{/useBeanValidation}} +import java.util.List; +import java.util.Map; +{{#jdk8-no-delegate}} +import java.util.Optional; +{{/jdk8-no-delegate}} +{{^jdk8-no-delegate}} + {{#useOptional}} +import java.util.Optional; + {{/useOptional}} +{{/jdk8-no-delegate}} +{{#async}} +import java.util.concurrent.{{^jdk8}}Callable{{/jdk8}}{{#jdk8}}CompletableFuture{{/jdk8}}; +{{/async}} +{{>generatedAnnotation}} +{{#useBeanValidation}} +@Validated +{{/useBeanValidation}} +@Api(value = "{{{baseName}}}", tags = "All") +{{#operations}} +{{#virtualService}} +@VirtualService +{{/virtualService}} +public interface {{classname}} { +{{#jdk8-default-interface}} + {{^isDelegate}} + {{^reactive}} + + default Optional getRequest() { + return Optional.empty(); + } + {{/reactive}} + {{/isDelegate}} + {{#isDelegate}} + + default {{classname}}Delegate getDelegate() { + return new {{classname}}Delegate() {}; + } + {{/isDelegate}} +{{/jdk8-default-interface}} +{{#operation}} + + /** + * {{httpMethod}} {{{path}}}{{#summary}} : {{.}}{{/summary}} + {{#notes}} + * {{.}} + {{/notes}} + * + {{#allParams}} + * @param {{paramName}} {{description}}{{#required}} (required){{/required}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}} + {{/allParams}} + * @return {{#responses}}{{message}} (status code {{code}}){{^-last}} + * or {{/-last}}{{/responses}} + {{#isDeprecated}} + * @deprecated + {{/isDeprecated}} + {{#externalDocs}} + * {{description}} + * @see {{summary}} Documentation + {{/externalDocs}} + */ + {{#virtualService}} + @ApiVirtual + {{/virtualService}} + @ApiOperation(value = "{{{summary}}}", nickname = "{{{operationId}}}", notes = "{{{notes}}}"{{#returnBaseType}}, response = {{{returnBaseType}}}.class{{/returnBaseType}}{{#returnContainer}}, responseContainer = "{{{returnContainer}}}"{{/returnContainer}}{{#hasAuthMethods}}, authorizations = { + {{#authMethods}}{{#isOAuth}}@Authorization(value = "{{name}}", scopes = { + {{#scopes}}@AuthorizationScope(scope = "{{scope}}", description = "{{description}}"){{^-last}}, + {{/-last}}{{/scopes}} }){{^-last}},{{/-last}}{{/isOAuth}} + {{^isOAuth}}@Authorization(value = "{{name}}"){{^-last}},{{/-last}} + {{/isOAuth}}{{/authMethods}} }{{/hasAuthMethods}}, tags={ {{#vendorExtensions.x-tags}}"{{tag}}",{{/vendorExtensions.x-tags}} }) + @ApiResponses(value = { {{#responses}} + @ApiResponse(code = {{{code}}}, message = "{{{message}}}"{{#baseType}}, response = {{{baseType}}}.class{{/baseType}}{{#containerType}}, responseContainer = "{{{containerType}}}"{{/containerType}}){{^-last}},{{/-last}}{{/responses}} }) + {{#implicitHeaders}} + @ApiImplicitParams({ + {{#headerParams}} + {{>implicitHeader}} + {{/headerParams}} + }) + {{/implicitHeaders}} + @RequestMapping( + method = RequestMethod.{{httpMethod}}, + value = "{{{path}}}"{{#singleContentTypes}}{{#hasProduces}}, + produces = "{{{vendorExtensions.x-accepts}}}"{{/hasProduces}}{{#hasConsumes}}, + consumes = "{{{vendorExtensions.x-contentType}}}"{{/hasConsumes}}{{/singleContentTypes}}{{^singleContentTypes}}{{#hasProduces}}, + produces = { {{#produces}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/produces}} }{{/hasProduces}}{{#hasConsumes}}, + consumes = { {{#consumes}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/consumes}} }{{/hasConsumes}}{{/singleContentTypes}} + ) + {{#jdk8-default-interface}}default {{/jdk8-default-interface}}{{#responseWrapper}}{{.}}<{{/responseWrapper}}ResponseEntity<{{>returnTypes}}>{{#responseWrapper}}>{{/responseWrapper}} {{#delegate-method}}_{{/delegate-method}}{{operationId}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{>cookieParams}}{{^-last}},{{/-last}}{{#-last}}{{#reactive}}, {{/reactive}}{{/-last}}{{/allParams}}{{#reactive}}@ApiIgnore final ServerWebExchange exchange{{/reactive}}{{#vendorExtensions.x-spring-paginated}}, @ApiIgnore final Pageable pageable{{/vendorExtensions.x-spring-paginated}}){{^jdk8-default-interface}};{{/jdk8-default-interface}}{{#jdk8-default-interface}}{{#unhandledException}} throws Exception{{/unhandledException}} { + {{#delegate-method}} + return {{operationId}}({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#reactive}}{{#hasParams}}, {{/hasParams}}exchange{{/reactive}}{{#vendorExtensions.x-spring-paginated}}, pageable{{/vendorExtensions.x-spring-paginated}}); + } + + // Override this method + {{#jdk8-default-interface}}default {{/jdk8-default-interface}} {{#responseWrapper}}{{.}}<{{/responseWrapper}}ResponseEntity<{{>returnTypes}}>{{#responseWrapper}}>{{/responseWrapper}} {{operationId}}({{#allParams}}{{^isFile}}{{^isBodyParam}}{{>optionalDataType}}{{/isBodyParam}}{{#isBodyParam}}{{^reactive}}{{{dataType}}}{{/reactive}}{{#reactive}}{{^isArray}}Mono<{{{dataType}}}>{{/isArray}}{{#isArray}}Flux<{{{baseType}}}>{{/isArray}}{{/reactive}}{{/isBodyParam}}{{/isFile}}{{#isFile}}{{#reactive}}Flux{{/reactive}}{{^reactive}}MultipartFile{{/reactive}}{{/isFile}} {{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#reactive}}{{#hasParams}}, {{/hasParams}}@ApiIgnore final ServerWebExchange exchange{{/reactive}}{{#vendorExtensions.x-spring-paginated}}, @ApiIgnore final Pageable pageable{{/vendorExtensions.x-spring-paginated}}){{#unhandledException}} throws Exception{{/unhandledException}} { + {{/delegate-method}} + {{^isDelegate}} + {{>methodBody}} + {{/isDelegate}} + {{#isDelegate}} + return getDelegate().{{operationId}}({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#reactive}}{{#hasParams}}, {{/hasParams}}exchange{{/reactive}}{{#vendorExtensions.x-spring-paginated}}, pageable{{/vendorExtensions.x-spring-paginated}}); + {{/isDelegate}} + }{{/jdk8-default-interface}} + +{{/operation}} +} +{{/operations}} \ No newline at end of file diff --git a/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/beanValidationCore.mustache b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/beanValidationCore.mustache new file mode 100644 index 0000000000..e3c19c6474 --- /dev/null +++ b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/beanValidationCore.mustache @@ -0,0 +1,26 @@ +{{{ vendorExtensions.x-constraints }}} +{{#errorMessage}}@Mandatory(errorMessage="{{{pattern}}}") {{/errorMessage}} +{{#pattern}}@Pattern(regexp="{{{pattern}}}") {{/pattern}}{{! +minLength && maxLength set +}}{{#minLength}}{{#maxLength}}@Size(min={{minLength}},max={{maxLength}}) {{/maxLength}}{{/minLength}}{{! +minLength set, maxLength not +}}{{#minLength}}{{^maxLength}}@Size(min={{minLength}}) {{/maxLength}}{{/minLength}}{{! +minLength not set, maxLength set +}}{{^minLength}}{{#maxLength}}@Size(max={{maxLength}}) {{/maxLength}}{{/minLength}}{{! +@Size: minItems && maxItems set +}}{{#minItems}}{{#maxItems}}@Size(min={{minItems}},max={{maxItems}}) {{/maxItems}}{{/minItems}}{{! +@Size: minItems set, maxItems not +}}{{#minItems}}{{^maxItems}}@Size(min={{minItems}}) {{/maxItems}}{{/minItems}}{{! +@Size: minItems not set && maxItems set +}}{{^minItems}}{{#maxItems}}@Size(max={{maxItems}}) {{/maxItems}}{{/minItems}}{{! +@Email: useBeanValidation set && isEmail && java8 set +}}{{#useBeanValidation}}{{#isEmail}}{{#java8}}@javax.validation.constraints.Email{{/java8}}{{/isEmail}}{{/useBeanValidation}}{{! +@Email: performBeanValidation set && isEmail && not java8 set +}}{{#performBeanValidation}}{{#isEmail}}{{^java8}}@org.hibernate.validator.constraints.Email{{/java8}}{{/isEmail}}{{/performBeanValidation}}{{! +check for integer or long / all others=decimal type with @Decimal* +isInteger set +}}{{#isInteger}}{{#minimum}}@Min({{minimum}}){{/minimum}}{{#maximum}} @Max({{maximum}}) {{/maximum}}{{/isInteger}}{{! +isLong set +}}{{#isLong}}{{#minimum}}@Min({{minimum}}L){{/minimum}}{{#maximum}} @Max({{maximum}}L) {{/maximum}}{{/isLong}}{{! +Not Integer, not Long => we have a decimal value! +}}{{^isInteger}}{{^isLong}}{{#minimum}}@DecimalMin({{#exclusiveMinimum}}value={{/exclusiveMinimum}}"{{minimum}}"{{#exclusiveMinimum}},inclusive=false{{/exclusiveMinimum}}){{/minimum}}{{#maximum}} @DecimalMax({{#exclusiveMaximum}}value={{/exclusiveMaximum}}"{{maximum}}"{{#exclusiveMaximum}},inclusive=false{{/exclusiveMaximum}}) {{/maximum}}{{/isLong}}{{/isInteger}} \ No newline at end of file diff --git a/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/cookieParams.mustache b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/cookieParams.mustache new file mode 100644 index 0000000000..e21bd9ff4b --- /dev/null +++ b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/cookieParams.mustache @@ -0,0 +1 @@ +{{#isCookieParam}}{{#useBeanValidation}}{{>beanValidationQueryParams}}{{/useBeanValidation}}@ApiParam(value = "{{{description}}}"{{#required}},required=true{{/required}}{{#allowableValues}}, allowableValues = "{{#enumVars}}{{#lambdaEscapeDoubleQuote}}{{{value}}}{{/lambdaEscapeDoubleQuote}}{{^-last}}, {{/-last}}{{#-last}}{{/-last}}{{/enumVars}}"{{/allowableValues}}{{^isContainer}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}{{/isContainer}}) @CookieValue("{{baseName}}") {{>optionalDataType}} {{paramName}}{{/isCookieParam}} \ No newline at end of file diff --git a/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/enum.mustache b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/enum.mustache new file mode 100644 index 0000000000..3cdae7f3cc --- /dev/null +++ b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/enum.mustache @@ -0,0 +1,31 @@ +class {{classname}} { + /// The underlying value of this enum member. + {{dataType}} value; + + {{classname}}._internal(this.value); + {{ vendorExtensions.x-enum-varnames }} + {{ vendorExtensions.x-enum-descriptions }} + {{#allowableValues}} + {{#enumVars}} + {{#description}} + /// {{description}} + {{/description}} + static {{classname}} {{name}} = {{classname}}._internal({{{value}}}); + {{/enumVars}} + {{/allowableValues}} + + {{classname}}.fromJson(dynamic data) { + switch (data) { + {{#allowableValues}} + {{#enumVars}} + case {{{value}}}: value = data; break; + {{/enumVars}} + {{/allowableValues}} + default: throw('Unknown enum value to decode: $data'); + } + } + + static dynamic encode({{classname}} data) { + return data.value; + } +} \ No newline at end of file diff --git a/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/model.mustache b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/model.mustache new file mode 100644 index 0000000000..d9329b40d3 --- /dev/null +++ b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/model.mustache @@ -0,0 +1,42 @@ +package {{package}}; + +{{#imports}}import {{import}}; +{{/imports}} +import com.fasterxml.jackson.databind.annotation.*; +import com.fasterxml.jackson.annotation.*; +import com.baeldung.openapi.petstore.validation.Camelcase; +{{^supportJava6}} +import java.util.Objects; +import java.util.Arrays; +{{/supportJava6}} +{{#supportJava6}} +import org.apache.commons.lang3.ObjectUtils; +{{/supportJava6}} +{{#imports}} +import {{import}}; +{{/imports}} +{{#serializableModel}} +import java.io.Serializable; +{{/serializableModel}} +{{#jackson}} +{{#withXml}} +import com.fasterxml.jackson.dataformat.xml.annotation.*; +{{/withXml}} +{{/jackson}} +{{#withXml}} +import javax.xml.bind.annotation.*; +{{/withXml}} +{{#parcelableModel}} +import android.os.Parcelable; +import android.os.Parcel; +{{/parcelableModel}} +{{#useBeanValidation}} +import javax.validation.constraints.*; +import javax.validation.Valid; +{{/useBeanValidation}} + +{{#models}} +{{#model}} +{{#isEnum}}{{>modelEnum}}{{/isEnum}}{{^isEnum}}{{>pojo}}{{/isEnum}} +{{/model}} +{{/models}} \ No newline at end of file diff --git a/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/modelEnum.mustache b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/modelEnum.mustache new file mode 100644 index 0000000000..29f27bd851 --- /dev/null +++ b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/openapi/templates/modelEnum.mustache @@ -0,0 +1,68 @@ +{{#jackson}} +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +{{/jackson}} +{{#gson}} +import java.io.IOException; +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +{{/gson}} + +/** + * {{^description}}Gets or Sets {{{name}}}{{/description}}{{#description}}{{description}}{{/description}} + */ +{{#gson}} +@JsonAdapter({{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}.Adapter.class) +{{/gson}} +public enum {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} { + {{#allowableValues}}{{#enumVars}} + {{{name}}}({{{value}}}){{^-last}}, + {{/-last}}{{#-last}};{{/-last}}{{/enumVars}}{{/allowableValues}} + + private {{{dataType}}} value; + + {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}({{{dataType}}} value) { + this.value = value; + } + +{{#jackson}} + @JsonValue +{{/jackson}} + public {{{dataType}}} getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + +{{#jackson}} + @JsonCreator +{{/jackson}} + public static {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} fromValue{{#jackson}}({{{dataType}}} value){{/jackson}}{{^jackson}}(String text){{/jackson}} { + for ({{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} b : {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}.values()) { + if ({{#jackson}}b.value.equals(value){{/jackson}}{{^jackson}}String.valueOf(b.value).equals(text){{/jackson}}) { + return b; + } + } + throw new UlpValidationException(UlpBundleKey.{{vendorExtensions.x-enum-invalidtag}}); + } +{{#gson}} + + public static class Adapter extends TypeAdapter<{{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}> { + @Override + public void write(final JsonWriter jsonWriter, final {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} enumeration) throws IOException { + jsonWriter.value(enumeration.getValue()); + } + + @Override + public {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} read(final JsonReader jsonReader) throws IOException { + {{#isNumber}}BigDecimal value = new BigDecimal(jsonReader.nextDouble()){{/isNumber}}{{^isNumber}}{{#isInteger}}Integer value {{/isInteger}}{{^isInteger}}String value {{/isInteger}}= jsonReader.{{#isInteger}}nextInt(){{/isInteger}}{{^isInteger}}nextString(){{/isInteger}}{{/isNumber}}; + return {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}.fromValue({{#jackson}}value{{/jackson}}{{^jackson}}String.valueOf(value){{/jackson}}); + } + } +{{/gson}} +} \ No newline at end of file diff --git a/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/petstore.yml b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/petstore.yml new file mode 100644 index 0000000000..c9884c01e8 --- /dev/null +++ b/spring-swagger-codegen/custom-validations-opeanpi-codegen/src/main/resources/petstore.yml @@ -0,0 +1,65 @@ +openapi: 3.0.1 +info: + version: "1.0" + title: PetStore +paths: + /pets: + post: + tags: + - pet + summary: Add a new pet to the store + description: Add a new pet to the store + operationId: addPet + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Pet' + responses: + '201': + description: default response, returning the new pet id + content: + application/json: + schema: + type: integer + '400': + description: Invalid input + get: + tags: + - pet + summary: Finds Pets by name + description: 'Find pets by name' + operationId: findPetsByName + parameters: + - name: name + in: query + schema: + type: string + description: Tags to filter by + x-constraints: "@Camelcase(required = true)" + responses: + '200': + description: default response + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + '400': + description: Invalid name value +components: + schemas: + Pet: + type: object + required: + - id + - name + properties: + id: + type: integer + format: int64 + name: + type: string + x-constraints: "@Camelcase(required = true)" \ No newline at end of file