From a9069e83600057f7d64e699ccc7dffb82d98b801 Mon Sep 17 00:00:00 2001 From: jfiala Date: Sat, 12 Nov 2016 22:47:31 +0100 Subject: [PATCH] add perform beanvalidation flag to ok-http-gson #2549 --- .../codegen/languages/JavaClientCodegen.java | 42 ++++++++--- .../PerformBeanValidationFeatures.java | 10 +++ .../Java/BeanValidationException.mustache | 27 +++++++ .../Java/beanValidationQueryParams.mustache | 1 + .../Java/libraries/okhttp-gson/api.mustache | 74 ++++++++++++++++--- .../Java/libraries/okhttp-gson/pom.mustache | 17 ++++- 6 files changed, 149 insertions(+), 22 deletions(-) create mode 100644 modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/features/PerformBeanValidationFeatures.java create mode 100644 modules/swagger-codegen/src/main/resources/Java/BeanValidationException.mustache create mode 100644 modules/swagger-codegen/src/main/resources/Java/beanValidationQueryParams.mustache diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavaClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavaClientCodegen.java index 3c574ccebba..47d1f4232ae 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavaClientCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavaClientCodegen.java @@ -1,18 +1,29 @@ package io.swagger.codegen.languages; -import io.swagger.codegen.*; -import io.swagger.codegen.languages.features.BeanValidationFeatures; +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.File; -import java.util.*; -import java.util.regex.Pattern; +import io.swagger.codegen.CliOption; +import io.swagger.codegen.CodegenConstants; +import io.swagger.codegen.CodegenModel; +import io.swagger.codegen.CodegenOperation; +import io.swagger.codegen.CodegenProperty; +import io.swagger.codegen.CodegenType; +import io.swagger.codegen.SupportingFile; +import io.swagger.codegen.languages.features.BeanValidationFeatures; +import io.swagger.codegen.languages.features.PerformBeanValidationFeatures; -public class JavaClientCodegen extends AbstractJavaCodegen implements BeanValidationFeatures { +public class JavaClientCodegen extends AbstractJavaCodegen + implements BeanValidationFeatures, PerformBeanValidationFeatures { static final String MEDIA_TYPE = "mediaType"; @SuppressWarnings("hiding") @@ -28,6 +39,7 @@ public class JavaClientCodegen extends AbstractJavaCodegen implements BeanValida protected boolean useRxJava = false; protected boolean parcelableModel = false; protected boolean useBeanValidation = false; + protected boolean performBeanValidation = false; public JavaClientCodegen() { super(); @@ -42,6 +54,7 @@ public class JavaClientCodegen extends AbstractJavaCodegen implements BeanValida cliOptions.add(CliOption.newBoolean(PARCELABLE_MODEL, "Whether to generate models for Android that implement Parcelable with the okhttp-gson library.")); cliOptions.add(CliOption.newBoolean(SUPPORT_JAVA6, "Whether to support Java6 with the Jersey1 library.")); cliOptions.add(CliOption.newBoolean(USE_BEANVALIDATION, "Use BeanValidation API annotations")); + cliOptions.add(CliOption.newBoolean(PERFORM_BEANVALIDATION, "Perform BeanValidation")); supportedLibraries.put("jersey1", "HTTP client: Jersey client 1.19.1. JSON processing: Jackson 2.7.0. Enable Java6 support using '-DsupportJava6=true'."); supportedLibraries.put("feign", "HTTP client: Netflix Feign 8.16.0. JSON processing: Jackson 2.7.0"); @@ -88,11 +101,11 @@ public class JavaClientCodegen extends AbstractJavaCodegen implements BeanValida additionalProperties.put(PARCELABLE_MODEL, parcelableModel); if (additionalProperties.containsKey(USE_BEANVALIDATION)) { - boolean useBeanValidationProp = Boolean.valueOf(additionalProperties.get(USE_BEANVALIDATION).toString()); - this.setUseBeanValidation(useBeanValidationProp); + this.setUseBeanValidation(convertPropertyToBooleanAndWriteBack(USE_BEANVALIDATION)); + } - // write back as boolean - additionalProperties.put(USE_BEANVALIDATION, useBeanValidationProp); + if (additionalProperties.containsKey(PERFORM_BEANVALIDATION)) { + this.setPerformBeanValidation(convertPropertyToBooleanAndWriteBack(PERFORM_BEANVALIDATION)); } final String invokerFolder = (sourceFolder + '/' + invokerPackage).replace(".", "/"); @@ -122,6 +135,11 @@ public class JavaClientCodegen extends AbstractJavaCodegen implements BeanValida supportingFiles.add(new SupportingFile("git_push.sh.mustache", "", "git_push.sh")); supportingFiles.add(new SupportingFile("gitignore.mustache", "", ".gitignore")); + if (performBeanValidation) { + supportingFiles.add(new SupportingFile("BeanValidationException.mustache", invokerFolder, + "BeanValidationException.java")); + } + //TODO: add doc to retrofit1 and feign if ( "feign".equals(getLibrary()) || "retrofit".equals(getLibrary()) ){ modelDocTemplateFiles.remove("model_doc.mustache"); @@ -302,6 +320,10 @@ public class JavaClientCodegen extends AbstractJavaCodegen implements BeanValida this.useBeanValidation = useBeanValidation; } + public void setPerformBeanValidation(boolean performBeanValidation) { + this.performBeanValidation = performBeanValidation; + } + final private static Pattern JSON_MIME_PATTERN = Pattern.compile("(?i)application\\/json(;.*)?"); final private static Pattern JSON_VENDOR_MIME_PATTERN = Pattern.compile("(?i)application\\/vnd.(.*)+json(;.*)?"); diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/features/PerformBeanValidationFeatures.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/features/PerformBeanValidationFeatures.java new file mode 100644 index 00000000000..3f30fb075f3 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/features/PerformBeanValidationFeatures.java @@ -0,0 +1,10 @@ +package io.swagger.codegen.languages.features; + +public interface PerformBeanValidationFeatures { + + // Language supports performing BeanValidation + public static final String PERFORM_BEANVALIDATION = "performBeanValidation"; + + public void setPerformBeanValidation(boolean performBeanValidation); + +} diff --git a/modules/swagger-codegen/src/main/resources/Java/BeanValidationException.mustache b/modules/swagger-codegen/src/main/resources/Java/BeanValidationException.mustache new file mode 100644 index 00000000000..ab8ef30b69b --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Java/BeanValidationException.mustache @@ -0,0 +1,27 @@ +package {{invokerPackage}}; + +import java.util.Set; + +import javax.validation.ConstraintViolation; +import javax.validation.ValidationException; + +public class BeanValidationException extends ValidationException { + /** + * + */ + private static final long serialVersionUID = -5294733947409491364L; + Set> violations; + + public BeanValidationException(Set> violations) { + this.violations = violations; + } + + public Set> getViolations() { + return violations; + } + + public void setViolations(Set> violations) { + this.violations = violations; + } + +} diff --git a/modules/swagger-codegen/src/main/resources/Java/beanValidationQueryParams.mustache b/modules/swagger-codegen/src/main/resources/Java/beanValidationQueryParams.mustache new file mode 100644 index 00000000000..cca08f4b2c4 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Java/beanValidationQueryParams.mustache @@ -0,0 +1 @@ +{{#required}} @NotNull{{/required}}{{#pattern}} @Pattern(regexp="{{pattern}}"){{/pattern}}{{#minLength}}{{#maxLength}} @Size(min={{minLength}},max={{maxLength}}){{/maxLength}}{{/minLength}}{{#minLength}}{{^maxLength}} @Size(min={{minLength}}){{/maxLength}}{{/minLength}}{{^minLength}}{{#maxLength}} @Size(max={{maxLength}}){{/maxLength}}{{/minLength}}{{#minItems}}{{#maxItems}} @Size(min={{minItems}},max={{maxItems}}){{/maxItems}}{{/minItems}}{{#minItems}}{{^maxItems}} @Size(min={{minItems}}){{/maxItems}}{{/minItems}}{{^minItems}}{{#maxItems}} @Size(max={{maxItems}}){{/maxItems}}{{/minItems}}{{#minimum}}/* @Min({{minimum}}) */{{/minimum}}{{#maximum}}/* @Max({{maximum}}) */{{/maximum}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/Java/libraries/okhttp-gson/api.mustache b/modules/swagger-codegen/src/main/resources/Java/libraries/okhttp-gson/api.mustache index 4f991f21936..1aed47562b9 100644 --- a/modules/swagger-codegen/src/main/resources/Java/libraries/okhttp-gson/api.mustache +++ b/modules/swagger-codegen/src/main/resources/Java/libraries/okhttp-gson/api.mustache @@ -10,11 +10,25 @@ import {{invokerPackage}}.Configuration; import {{invokerPackage}}.Pair; import {{invokerPackage}}.ProgressRequestBody; import {{invokerPackage}}.ProgressResponseBody; +import {{invokerPackage}}.BeanValidationException; import com.google.gson.reflect.TypeToken; import java.io.IOException; +{{#useBeanValidation}} +import javax.validation.constraints.*; +{{/useBeanValidation}} +{{#performBeanValidation}} +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.ValidatorFactory; +import javax.validation.executable.ExecutableValidator; +import java.util.Set; +import java.lang.reflect.Method; +import java.lang.reflect.Type; +{{/performBeanValidation}} + {{#imports}}import {{import}}; {{/imports}} @@ -50,13 +64,7 @@ public class {{classname}} { /* Build call for {{operationId}} */ private com.squareup.okhttp.Call {{operationId}}Call({{#allParams}}{{{dataType}}} {{paramName}}, {{/allParams}}final ProgressResponseBody.ProgressListener progressListener, final ProgressRequestBody.ProgressRequestListener progressRequestListener) throws ApiException { Object {{localVariablePrefix}}localVarPostBody = {{#bodyParam}}{{paramName}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}}; - {{#allParams}}{{#required}} - // verify the required parameter '{{paramName}}' is set - if ({{paramName}} == null) { - throw new ApiException("Missing the required parameter '{{paramName}}' when calling {{operationId}}(Async)"); - } - {{/required}}{{/allParams}} - + // create path and map variables String {{localVariablePrefix}}localVarPath = "{{{path}}}".replaceAll("\\{format\\}","json"){{#pathParams}} .replaceAll("\\{" + "{{baseName}}" + "\\}", {{localVariablePrefix}}apiClient.escapeString({{{paramName}}}.toString())){{/pathParams}}; @@ -99,6 +107,52 @@ public class {{classname}} { String[] {{localVariablePrefix}}localVarAuthNames = new String[] { {{#authMethods}}"{{name}}"{{#hasMore}}, {{/hasMore}}{{/authMethods}} }; return {{localVariablePrefix}}apiClient.buildCall({{localVariablePrefix}}localVarPath, "{{httpMethod}}", {{localVariablePrefix}}localVarQueryParams, {{localVariablePrefix}}localVarPostBody, {{localVariablePrefix}}localVarHeaderParams, {{localVariablePrefix}}localVarFormParams, {{localVariablePrefix}}localVarAuthNames, progressRequestListener); + } + + private com.squareup.okhttp.Call {{operationId}}ValidateBeforeCall({{#allParams}}{{{dataType}}} {{paramName}}, {{/allParams}}final ProgressResponseBody.ProgressListener progressListener, final ProgressRequestBody.ProgressRequestListener progressRequestListener) throws ApiException { + {{^performBeanValidation}} + {{#allParams}}{{#required}} + // verify the required parameter '{{paramName}}' is set + if ({{paramName}} == null) { + throw new ApiException("Missing the required parameter '{{paramName}}' when calling {{operationId}}(Async)"); + } + {{/required}}{{/allParams}} + + com.squareup.okhttp.Call {{localVariablePrefix}}call = {{operationId}}Call({{#allParams}}{{paramName}}, {{/allParams}}progressListener, progressRequestListener); + return {{localVariablePrefix}}call; + + {{/performBeanValidation}} + {{#performBeanValidation}} + try { + ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); + ExecutableValidator executableValidator = factory.getValidator().forExecutables(); + + Object[] parameterValues = { {{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}} }; + Method method = this.getClass().getMethod("{{operationId}}WithHttpInfo"{{#allParams}}, {{#isListContainer}}java.util.List{{/isListContainer}}{{#isMapContainer}}java.util.Map{{/isMapContainer}}{{^isListContainer}}{{^isMapContainer}}{{{dataType}}}{{/isMapContainer}}{{/isListContainer}}.class{{/allParams}}); + Set> violations = executableValidator.validateParameters(this, method, + parameterValues); + + if (violations.size() == 0) { + com.squareup.okhttp.Call {{localVariablePrefix}}call = {{operationId}}Call({{#allParams}}{{paramName}}, {{/allParams}}progressListener, progressRequestListener); + return {{localVariablePrefix}}call; + + } else { + Set> violationsObj = (Set>) violations; + throw new BeanValidationException(violationsObj); + } + } catch (NoSuchMethodException e) { + e.printStackTrace(); + throw new ApiException(e.getMessage()); + } catch (SecurityException e) { + e.printStackTrace(); + throw new ApiException(e.getMessage()); + } + + {{/performBeanValidation}} + + + + } /** @@ -120,8 +174,8 @@ public class {{classname}} { * @return ApiResponse<{{#returnType}}{{returnType}}{{/returnType}}{{^returnType}}Void{{/returnType}}> * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body */ - public ApiResponse<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}> {{operationId}}WithHttpInfo({{#allParams}}{{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) throws ApiException { - com.squareup.okhttp.Call {{localVariablePrefix}}call = {{operationId}}Call({{#allParams}}{{paramName}}, {{/allParams}}null, null); + public ApiResponse<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}> {{operationId}}WithHttpInfo({{#allParams}}{{#useBeanValidation}}{{>beanValidationQueryParams}}{{/useBeanValidation}}{{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) throws ApiException { + com.squareup.okhttp.Call {{localVariablePrefix}}call = {{operationId}}ValidateBeforeCall({{#allParams}}{{paramName}}, {{/allParams}}null, null); {{#returnType}}Type {{localVariablePrefix}}localVarReturnType = new TypeToken<{{{returnType}}}>(){}.getType(); return {{localVariablePrefix}}apiClient.execute({{localVariablePrefix}}call, {{localVariablePrefix}}localVarReturnType);{{/returnType}}{{^returnType}}return {{localVariablePrefix}}apiClient.execute({{localVariablePrefix}}call);{{/returnType}} } @@ -155,7 +209,7 @@ public class {{classname}} { }; } - com.squareup.okhttp.Call {{localVariablePrefix}}call = {{operationId}}Call({{#allParams}}{{paramName}}, {{/allParams}}progressListener, progressRequestListener); + com.squareup.okhttp.Call {{localVariablePrefix}}call = {{operationId}}ValidateBeforeCall({{#allParams}}{{paramName}}, {{/allParams}}progressListener, progressRequestListener); {{#returnType}}Type {{localVariablePrefix}}localVarReturnType = new TypeToken<{{{returnType}}}>(){}.getType(); {{localVariablePrefix}}apiClient.executeAsync({{localVariablePrefix}}call, {{localVariablePrefix}}localVarReturnType, {{localVariablePrefix}}callback);{{/returnType}}{{^returnType}}{{localVariablePrefix}}apiClient.executeAsync({{localVariablePrefix}}call, {{localVariablePrefix}}callback);{{/returnType}} return {{localVariablePrefix}}call; diff --git a/modules/swagger-codegen/src/main/resources/Java/libraries/okhttp-gson/pom.mustache b/modules/swagger-codegen/src/main/resources/Java/libraries/okhttp-gson/pom.mustache index 698c1a97f94..4e2e7e877c8 100644 --- a/modules/swagger-codegen/src/main/resources/Java/libraries/okhttp-gson/pom.mustache +++ b/modules/swagger-codegen/src/main/resources/Java/libraries/okhttp-gson/pom.mustache @@ -139,8 +139,21 @@ 1.1.0.Final provided - {{/useBeanValidation}} - + {{/useBeanValidation}} + {{#performBeanValidation}} + + + org.hibernate + hibernate-validator + 5.2.2.Final + + + javax.el + el-api + 2.2 + + {{/performBeanValidation}} + junit