From 87786f01452b66bb66ced662200fef6b7143f830 Mon Sep 17 00:00:00 2001 From: Nadezhda Makarkina Date: Mon, 9 Nov 2015 14:01:50 +0300 Subject: [PATCH 01/71] ensureUniqueParams default value has been mooved from description to the defaaultValue field --- .../src/main/java/io/swagger/codegen/CodegenConstants.java | 2 +- .../src/main/java/io/swagger/codegen/DefaultCodegen.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenConstants.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenConstants.java index a5bb97e5a931..f9c816df278c 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenConstants.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenConstants.java @@ -41,7 +41,7 @@ public class CodegenConstants { public static final String SORT_PARAMS_BY_REQUIRED_FLAG_DESC = "Sort method arguments to place required parameters before optional parameters."; public static final String ENSURE_UNIQUE_PARAMS = "ensureUniqueParams"; - public static final String ENSURE_UNIQUE_PARAMS_DESC = "Whether to ensure parameter names are unique in an operation (rename parameters that are not). Default: true"; + public static final String ENSURE_UNIQUE_PARAMS_DESC = "Whether to ensure parameter names are unique in an operation (rename parameters that are not)."; public static final String PACKAGE_NAME = "packageName"; public static final String PACKAGE_VERSION = "packageVersion"; diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/DefaultCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/DefaultCodegen.java index 3c8758fc15b8..663263ccbbf4 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/DefaultCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/DefaultCodegen.java @@ -445,7 +445,8 @@ public class DefaultCodegen { cliOptions.add(new CliOption(CodegenConstants.SORT_PARAMS_BY_REQUIRED_FLAG, CodegenConstants.SORT_PARAMS_BY_REQUIRED_FLAG_DESC).defaultValue("true")); - cliOptions.add(new CliOption(CodegenConstants.ENSURE_UNIQUE_PARAMS, CodegenConstants.ENSURE_UNIQUE_PARAMS_DESC)); + cliOptions.add(new CliOption(CodegenConstants.ENSURE_UNIQUE_PARAMS, CodegenConstants.ENSURE_UNIQUE_PARAMS_DESC) + .defaultValue("true")); } /** From be944650df1f77de0ffee33e63a15d6d3721d4e1 Mon Sep 17 00:00:00 2001 From: 317959997 Date: Thu, 26 Nov 2015 13:30:04 -0500 Subject: [PATCH 02/71] added initial Netflix Feign support --- .../codegen/languages/JavaClientCodegen.java | 15 +- .../Java/libraries/feign/ApiClient.mustache | 86 ++++++++ .../Java/libraries/feign/api.mustache | 34 ++++ .../libraries/feign/build.gradle.mustache | 113 +++++++++++ .../Java/libraries/feign/pom.mustache | 183 ++++++++++++++++++ 5 files changed, 425 insertions(+), 6 deletions(-) create mode 100644 modules/swagger-codegen/src/main/resources/Java/libraries/feign/ApiClient.mustache create mode 100644 modules/swagger-codegen/src/main/resources/Java/libraries/feign/api.mustache create mode 100644 modules/swagger-codegen/src/main/resources/Java/libraries/feign/build.gradle.mustache create mode 100644 modules/swagger-codegen/src/main/resources/Java/libraries/feign/pom.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 636f0157a525..1c2ccf2d6900 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 @@ -98,6 +98,7 @@ public class JavaClientCodegen extends DefaultCodegen implements CodegenConfig { .defaultValue("false")); supportedLibraries.put(DEFAULT_LIBRARY, "HTTP client: Jersey client 1.18. JSON processing: Jackson 2.4.2"); + supportedLibraries.put("feign", "HTTP client: Netflix Feign 8.1.1"); supportedLibraries.put("jersey2", "HTTP client: Jersey client 2.6"); supportedLibraries.put("okhttp-gson", "HTTP client: OkHttp 2.4.0. JSON processing: Gson 2.3.1"); supportedLibraries.put("retrofit", "HTTP client: OkHttp 2.4.0. JSON processing: Gson 2.3.1 (Retrofit 1.9.0)"); @@ -215,12 +216,14 @@ public class JavaClientCodegen extends DefaultCodegen implements CodegenConfig { supportingFiles.add(new SupportingFile("StringUtil.mustache", invokerFolder, "StringUtil.java")); final String authFolder = (sourceFolder + '/' + invokerPackage + ".auth").replace(".", "/"); - supportingFiles.add(new SupportingFile("auth/HttpBasicAuth.mustache", authFolder, "HttpBasicAuth.java")); - supportingFiles.add(new SupportingFile("auth/ApiKeyAuth.mustache", authFolder, "ApiKeyAuth.java")); - supportingFiles.add(new SupportingFile("auth/OAuth.mustache", authFolder, "OAuth.java")); - supportingFiles.add(new SupportingFile("auth/OAuthFlow.mustache", authFolder, "OAuthFlow.java")); + if (!"feign".equals(getLibrary())) { + supportingFiles.add(new SupportingFile("auth/HttpBasicAuth.mustache", authFolder, "HttpBasicAuth.java")); + supportingFiles.add(new SupportingFile("auth/ApiKeyAuth.mustache", authFolder, "ApiKeyAuth.java")); + supportingFiles.add(new SupportingFile("auth/OAuth.mustache", authFolder, "OAuth.java")); + supportingFiles.add(new SupportingFile("auth/OAuthFlow.mustache", authFolder, "OAuthFlow.java")); + } - if (!("retrofit".equals(getLibrary()) || "retrofit2".equals(getLibrary()))) { + if (!("feign".equals(getLibrary()) || "retrofit".equals(getLibrary()) || "retrofit2".equals(getLibrary()))) { supportingFiles.add(new SupportingFile("apiException.mustache", invokerFolder, "ApiException.java")); supportingFiles.add(new SupportingFile("Configuration.mustache", invokerFolder, "Configuration.java")); supportingFiles.add(new SupportingFile("JSON.mustache", invokerFolder, "JSON.java")); @@ -237,7 +240,7 @@ public class JavaClientCodegen extends DefaultCodegen implements CodegenConfig { } else if ("retrofit".equals(getLibrary()) || "retrofit2".equals(getLibrary())) { supportingFiles.add(new SupportingFile("auth/OAuthOkHttpClient.mustache", authFolder, "OAuthOkHttpClient.java")); supportingFiles.add(new SupportingFile("CollectionFormats.mustache", invokerFolder, "CollectionFormats.java")); - } else { + } else if (!"feign".equals(getLibrary())) { supportingFiles.add(new SupportingFile("TypeRef.mustache", invokerFolder, "TypeRef.java")); } } diff --git a/modules/swagger-codegen/src/main/resources/Java/libraries/feign/ApiClient.mustache b/modules/swagger-codegen/src/main/resources/Java/libraries/feign/ApiClient.mustache new file mode 100644 index 000000000000..7ce51e909ebc --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Java/libraries/feign/ApiClient.mustache @@ -0,0 +1,86 @@ +package {{invokerPackage}}; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import feign.Feign; +import feign.jackson.JacksonDecoder; +import feign.jackson.JacksonEncoder; +import feign.slf4j.Slf4jLogger; + +{{>generatedAnnotation}} +public class ApiClient { + public interface Api {} + + private ObjectMapper objectMapper; + private String basePath = "{{basePath}}"; + + public ApiClient() { + objectMapper = createObjectMapper(); + } + + public String getBasePath() { + return basePath; + } + + public ApiClient setBasePath(String basePath) { + this.basePath = basePath; + return this; + } + + private ObjectMapper createObjectMapper() { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING); + objectMapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING); + return objectMapper; + } + + /** + * Creates a feign client for given API interface. + * + * Usage: + * ApiClient apiClient = new ApiClient(); + * apiClient.setBasePath("http://localhost:8080"); + * XYZApi api = apiClient.buildClient(XYZApi.class); + * XYZResponse response = api.someMethod(...); + */ + public T buildClient(Class clientClass) { + return Feign.builder() + .encoder(new JacksonEncoder(objectMapper)) + .decoder(new JacksonDecoder(objectMapper)) +// enable for basic auth: +// .requestInterceptor(new feign.auth.BasicAuthRequestInterceptor(username, password)) + .logger(new Slf4jLogger()) + .target(clientClass, basePath); + } + + /** + * Select the Accept header's value from the given accepts array: + * if JSON exists in the given array, use it; + * otherwise use all of them (joining into a string) + * + * @param accepts The accepts array to select from + * @return The Accept header to use. If the given array is empty, + * null will be returned (not to set the Accept header explicitly). + */ + public String selectHeaderAccept(String[] accepts) { + if (accepts.length == 0) return null; + if (StringUtil.containsIgnoreCase(accepts, "application/json")) return "application/json"; + return StringUtil.join(accepts, ","); + } + + /** + * Select the Content-Type header's value from the given array: + * if JSON exists in the given array, use it; + * otherwise use the first one of the array. + * + * @param contentTypes The Content-Type array to select from + * @return The Content-Type header to use. If the given array is empty, + * JSON will be used. + */ + public String selectHeaderContentType(String[] contentTypes) { + if (contentTypes.length == 0) return "application/json"; + if (StringUtil.containsIgnoreCase(contentTypes, "application/json")) return "application/json"; + return contentTypes[0]; + } +} diff --git a/modules/swagger-codegen/src/main/resources/Java/libraries/feign/api.mustache b/modules/swagger-codegen/src/main/resources/Java/libraries/feign/api.mustache new file mode 100644 index 000000000000..9ffcb014a846 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Java/libraries/feign/api.mustache @@ -0,0 +1,34 @@ +package {{package}}; + +import {{invokerPackage}}.ApiException; +import {{invokerPackage}}.ApiClient; +import {{invokerPackage}}.Configuration; +import {{invokerPackage}}.Pair; +import {{invokerPackage}}.TypeRef; + +{{#imports}}import {{import}}; +{{/imports}} + +{{^fullJavaUtil}}import java.util.*; +{{/fullJavaUtil}} +import feign.*; + +{{>generatedAnnotation}} +public interface {{classname}} extends {{invokerPackage}}.ApiClient.Api { + +{{#operations}}{{#operation}} + /** + * {{summary}} + * {{notes}} +{{#allParams}} * @param {{paramName}} {{description}} +{{/allParams}} * @return {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}} + */ + @RequestLine("{{httpMethod}} {{{path}}}{{#hasParams}}?{{/hasParams}}{{#allParams}}{{paramName}}={{=<% %>=}}{<%paramName%>}<%={{ }}=%>{{#hasMore}}&{{/hasMore}}{{/allParams}}") + @Headers({ + {{#headerParams}}"{{paramName}}: {{=<% %>=}}{<%paramName%>}<%={{ }}=%>"{{#hasMore}}, + {{/hasMore}}{{/headerParams}} + }) + {{#returnType}}{{{returnType}}} {{/returnType}}{{^returnType}}void {{/returnType}}{{nickname}} ({{#allParams}}@Param("{{paramName}}") {{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) throws ApiException; + {{/operation}} +{{/operations}} +} diff --git a/modules/swagger-codegen/src/main/resources/Java/libraries/feign/build.gradle.mustache b/modules/swagger-codegen/src/main/resources/Java/libraries/feign/build.gradle.mustache new file mode 100644 index 000000000000..a528180df282 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Java/libraries/feign/build.gradle.mustache @@ -0,0 +1,113 @@ +group = '{{groupId}}' +version = '{{artifactVersion}}' + +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.2.2' + classpath 'com.github.dcendents:android-maven-plugin:1.2' + } +} + +repositories { + jcenter() +} + + +if(hasProperty('target') && target == 'android') { + + apply plugin: 'com.android.library' + apply plugin: 'com.github.dcendents.android-maven' + + android { + compileSdkVersion 22 + buildToolsVersion '22.0.0' + defaultConfig { + minSdkVersion 14 + targetSdkVersion 22 + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_7 + targetCompatibility JavaVersion.VERSION_1_7 + } + + // Rename the aar correctly + libraryVariants.all { variant -> + variant.outputs.each { output -> + def outputFile = output.outputFile + if (outputFile != null && outputFile.name.endsWith('.aar')) { + def fileName = "${project.name}-${variant.baseName}-${version}.aar" + output.outputFile = new File(outputFile.parent, fileName) + } + } + } + + dependencies { + provided 'javax.annotation:jsr250-api:1.0' + } + } + + afterEvaluate { + android.libraryVariants.all { variant -> + def task = project.tasks.create "jar${variant.name.capitalize()}", Jar + task.description = "Create jar artifact for ${variant.name}" + task.dependsOn variant.javaCompile + task.from variant.javaCompile.destinationDir + task.destinationDir = project.file("${project.buildDir}/outputs/jar") + task.archiveName = "${project.name}-${variant.baseName}-${version}.jar" + artifacts.add('archives', task); + } + } + + task sourcesJar(type: Jar) { + from android.sourceSets.main.java.srcDirs + classifier = 'sources' + } + + artifacts { + archives sourcesJar + } + +} else { + + apply plugin: 'java' + apply plugin: 'maven' + + sourceCompatibility = JavaVersion.VERSION_1_7 + targetCompatibility = JavaVersion.VERSION_1_7 + + install { + repositories.mavenInstaller { + pom.artifactId = '{{artifactId}}' + } + } + + task execute(type:JavaExec) { + main = System.getProperty('mainClass') + classpath = sourceSets.main.runtimeClasspath + } +} + +ext { + swagger_annotations_version = "1.5.0" + jackson_version = "2.6.3" + feign_version = "8.1.1" + jodatime_version = "2.5" + junit_version = "4.12" +} + +dependencies { + compile "io.swagger:swagger-annotations:$swagger_annotations_version" + compile "com.netflix.feign:feign-core:$feign_version" + compile "com.netflix.feign:feign-jackson:$feign_version" + compile "com.netflix.feign:feign-slf4j:$feign_version" + compile "com.fasterxml.jackson.core:jackson-core:$jackson_version" + compile "com.fasterxml.jackson.core:jackson-annotations:$jackson_version" + compile "com.fasterxml.jackson.core:jackson-databind:$jackson_version" + compile "com.fasterxml.jackson.datatype:jackson-datatype-joda:2.1.5" + compile "joda-time:joda-time:$jodatime_version" + compile "com.brsanthu:migbase64:2.2" + testCompile "junit:junit:$junit_version" +} diff --git a/modules/swagger-codegen/src/main/resources/Java/libraries/feign/pom.mustache b/modules/swagger-codegen/src/main/resources/Java/libraries/feign/pom.mustache new file mode 100644 index 000000000000..e8069b829310 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Java/libraries/feign/pom.mustache @@ -0,0 +1,183 @@ + + 4.0.0 + {{groupId}} + {{artifactId}} + jar + {{artifactId}} + {{artifactVersion}} + + scm:git:git@github.com:swagger-api/swagger-mustache.git + scm:git:git@github.com:swagger-api/swagger-codegen.git + https://github.com/swagger-api/swagger-codegen + + + 2.2.0 + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.12 + + + + loggerPath + conf/log4j.properties + + + -Xms512m -Xmx1500m + methods + pertest + + + + maven-dependency-plugin + + + package + + copy-dependencies + + + ${project.build.directory}/lib + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.2 + + + + jar + test-jar + + + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + add_sources + generate-sources + + add-source + + + + src/main/java + + + + + add_test_sources + generate-test-sources + + add-test-source + + + + src/test/java + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.6 + 1.6 + + + + + + + io.swagger + swagger-annotations + ${swagger-annotations-version} + + + + + com.netflix.feign + feign-core + ${feign-version} + + + com.netflix.feign + feign-jackson + ${feign-version} + + + com.netflix.feign + feign-slf4j + ${feign-version} + + + + + com.fasterxml.jackson.core + jackson-core + ${jackson-version} + + + com.fasterxml.jackson.core + jackson-annotations + ${jackson-version} + + + com.fasterxml.jackson.core + jackson-databind + ${jackson-version} + + + com.fasterxml.jackson.datatype + jackson-datatype-joda + 2.1.5 + + + joda-time + joda-time + ${jodatime-version} + + + + + com.brsanthu + migbase64 + 2.2 + + + + + junit + junit + ${junit-version} + test + + + + 1.5.0 + 8.1.1 + 2.6.3 + 2.5 + 4.12 + 1.0.0 + + From 077a24f694c173e6c842ef61f9c47001518a2651 Mon Sep 17 00:00:00 2001 From: 317959997 Date: Thu, 26 Nov 2015 13:34:33 -0500 Subject: [PATCH 03/71] updated README.md on the new Netflix Feign library --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ef321e4bb595..2b1fa95364e9 100644 --- a/README.md +++ b/README.md @@ -353,9 +353,10 @@ CONFIG OPTIONS library template (sub-template) to use: - HTTP client: Jersey client 1.18. JSON processing: Jackson 2.4.2 jersey2 - HTTP client: Jersey client 2.6 + feign - HTTP client: Netflix Feign 8.1.1. JSON processing: Jackson 2.6.3 okhttp-gson - HTTP client: OkHttp 2.4.0. JSON processing: Gson 2.3.1 retrofit - HTTP client: OkHttp 2.4.0. JSON processing: Gson 2.3.1 (Retrofit 1.9.0) - retrofit2 - HTTP client: OkHttp 2.5.0. JSON processing: Gson 2.4 (Retrofit 2.0.0-beta2) + retrofit2 - HTTP client: OkHttp 2.5.0. JSON processing: Gson 2.4 (Retrofit 2.0.0-beta2) ``` Your config file for java can look like @@ -365,6 +366,7 @@ Your config file for java can look like "groupId":"com.my.company", "artifactId":"MyClent", "artifactVersion":"1.2.0" + "library":"feign" } ``` From 3cf8f24a079abf6c5cf0eb01771c6141cfe65aed Mon Sep 17 00:00:00 2001 From: 317959997 Date: Thu, 26 Nov 2015 13:37:19 -0500 Subject: [PATCH 04/71] updated README.md on the new Netflix Feign library --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 2b1fa95364e9..e66a9e397a80 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ [![Build Status](https://travis-ci.org/swagger-api/swagger-codegen.png)](https://travis-ci.org/swagger-api/swagger-codegen) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.swagger/swagger-codegen-project/badge.svg?style=plastic)](https://maven-badges.herokuapp.com/maven-central/io.swagger/swagger-codegen-project) +This is a fork with added support for [Netflix Feign](https://github.com/Netflix/feign) + ## Overview This is the swagger codegen project, which allows generation of client libraries automatically from a Swagger-compliant server. From 4b9b7a6a012190349018a6b562185381fbd06c53 Mon Sep 17 00:00:00 2001 From: 317959997 Date: Thu, 26 Nov 2015 13:37:58 -0500 Subject: [PATCH 05/71] updated README.md on the new Netflix Feign library --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e66a9e397a80..4a96ff7f7fc2 100644 --- a/README.md +++ b/README.md @@ -367,7 +367,7 @@ Your config file for java can look like { "groupId":"com.my.company", "artifactId":"MyClent", - "artifactVersion":"1.2.0" + "artifactVersion":"1.2.0", "library":"feign" } ``` From 7272cb0feb1d48f4502e7488b5b9ec161eaa6062 Mon Sep 17 00:00:00 2001 From: 317959997 Date: Fri, 27 Nov 2015 12:21:59 -0500 Subject: [PATCH 06/71] fixed feign api template --- .../src/main/resources/Java/libraries/feign/api.mustache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/swagger-codegen/src/main/resources/Java/libraries/feign/api.mustache b/modules/swagger-codegen/src/main/resources/Java/libraries/feign/api.mustache index 9ffcb014a846..772079eebdbe 100644 --- a/modules/swagger-codegen/src/main/resources/Java/libraries/feign/api.mustache +++ b/modules/swagger-codegen/src/main/resources/Java/libraries/feign/api.mustache @@ -23,7 +23,7 @@ public interface {{classname}} extends {{invokerPackage}}.ApiClient.Api { {{#allParams}} * @param {{paramName}} {{description}} {{/allParams}} * @return {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}} */ - @RequestLine("{{httpMethod}} {{{path}}}{{#hasParams}}?{{/hasParams}}{{#allParams}}{{paramName}}={{=<% %>=}}{<%paramName%>}<%={{ }}=%>{{#hasMore}}&{{/hasMore}}{{/allParams}}") + @RequestLine("{{httpMethod}} {{{path}}}{{#hasQueryParams}}?{{/hasQueryParams}}{{#queryParams}}{{paramName}}={{=<% %>=}}{<%paramName%>}<%={{ }}=%>{{#hasMore}}&{{/hasMore}}{{/queryParams}}") @Headers({ {{#headerParams}}"{{paramName}}: {{=<% %>=}}{<%paramName%>}<%={{ }}=%>"{{#hasMore}}, {{/hasMore}}{{/headerParams}} From a7f225b6ac766737a28b7d9e8199a90eddbed0ae Mon Sep 17 00:00:00 2001 From: 317959997 Date: Fri, 27 Nov 2015 12:25:00 -0500 Subject: [PATCH 07/71] added support for generating JMeter project from swagger --- README.md | 7 +- .../src/main/resources/JMeter/api.mustache | 178 ++++++++++++++++++ .../JMeter/testdata-localhost.mustache | 2 + .../services/io.swagger.codegen.CodegenConfig | 1 + 4 files changed, 185 insertions(+), 3 deletions(-) create mode 100644 modules/swagger-codegen/src/main/resources/JMeter/api.mustache create mode 100644 modules/swagger-codegen/src/main/resources/JMeter/testdata-localhost.mustache diff --git a/README.md b/README.md index 4a96ff7f7fc2..ba1266e0ef40 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # Swagger Code Generator -[![Build Status](https://travis-ci.org/swagger-api/swagger-codegen.png)](https://travis-ci.org/swagger-api/swagger-codegen) -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.swagger/swagger-codegen-project/badge.svg?style=plastic)](https://maven-badges.herokuapp.com/maven-central/io.swagger/swagger-codegen-project) +This is a fork with added support for generating -This is a fork with added support for [Netflix Feign](https://github.com/Netflix/feign) + - Java client using [Netflix Feign](https://github.com/Netflix/feign). + - [Apache JMeter](http://jmeter.apache.org/) project for testing REST endpoints. ## Overview This is the swagger codegen project, which allows generation of client libraries automatically from a Swagger-compliant server. @@ -279,6 +279,7 @@ FlaskConnexionCodegen.java JavaClientCodegen.java JavaInflectorServerCodegen.java JaxRSServerCodegen.java +JMeterCodegen.java NodeJSServerCodegen.java ObjcClientCodegen.java PerlClientCodegen.java diff --git a/modules/swagger-codegen/src/main/resources/JMeter/api.mustache b/modules/swagger-codegen/src/main/resources/JMeter/api.mustache new file mode 100644 index 000000000000..1af63c2d66dd --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/JMeter/api.mustache @@ -0,0 +1,178 @@ + + + + + + false + false + + + + host + localhost + = + + + port + 8080 + = + + + + + + + + + + testCases + ${__P(host,10)} + = + + + host + ${__P(host,localhost)} + = + + + port + ${__P(port,8080)} + = + {{#operations}}{{#operation}} + + testData.{{operationId}}File + ${__P(testData.{{operationId}}File,{{classname}}.csv)} + = + {{/operation}}{{/operations}} + + + + + + + + ${host} + ${port} + + + + + + 4 + + + {{#operations}}{{#operation}} + continue + + false + ${testCases} + + 1 + 1 + 1448391617000 + 1448391617000 + false + + + + + + {{#headerParams}} + + {{paramName}} + ${__RandomString(10,qwertyuiopasdfghjklzxcvbnm)} + {{/headerParams}} + + + + + + {{#queryParams}} + + false + 0 + = + true + {{paramName}} + {{/queryParams}} + + + + + + + + + {{vendorExtensions.x-path}} + {{httpMethod}} + true + false + true + false + HttpClient3.1 + false + + {{summary}} {{notes}} + + + + , + + ${testData.{{operationId}}File} + true + true + shareMode.all + false + + + + + + + ${httpStatusCode} + + Assertion.response_code + false + 8 + + + + {{/operation}} + {{/operations}} + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + false + false + false + false + false + false + 0 + true + true + + + + + + + + diff --git a/modules/swagger-codegen/src/main/resources/JMeter/testdata-localhost.mustache b/modules/swagger-codegen/src/main/resources/JMeter/testdata-localhost.mustache new file mode 100644 index 000000000000..48708a1d0fa4 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/JMeter/testdata-localhost.mustache @@ -0,0 +1,2 @@ +testCase,httpStatusCode{{#operations}}{{#operation}}{{#hasParams}},{{/hasParams}}{{#allParams}}{{paramName}}{{#hasMore}},{{/hasMore}}{{/allParams}}{{/operation}}{{/operations}} +Success,200{{#operations}}{{#operation}}{{#hasParams}},{{/hasParams}}{{#allParams}}0{{#hasMore}},{{/hasMore}}{{/allParams}}{{/operation}}{{/operations}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig b/modules/swagger-codegen/src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig index 5c607488d9b5..de31683a15fa 100644 --- a/modules/swagger-codegen/src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig +++ b/modules/swagger-codegen/src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig @@ -7,6 +7,7 @@ io.swagger.codegen.languages.FlaskConnexionCodegen io.swagger.codegen.languages.JavaClientCodegen io.swagger.codegen.languages.JaxRSServerCodegen io.swagger.codegen.languages.JavaInflectorServerCodegen +io.swagger.codegen.languages.JMeterCodegen io.swagger.codegen.languages.NodeJSServerCodegen io.swagger.codegen.languages.ObjcClientCodegen io.swagger.codegen.languages.PerlClientCodegen From 845dd229420c29d2ab9daab260971e7f49c791bc Mon Sep 17 00:00:00 2001 From: 317959997 Date: Mon, 30 Nov 2015 10:18:29 -0500 Subject: [PATCH 08/71] added missing JMeter files --- gen-config.json | 1 + modules/swagger-codegen/pom.xml | 4 +++- pom.xml | 6 +++++- 3 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 gen-config.json diff --git a/gen-config.json b/gen-config.json new file mode 100644 index 000000000000..4ec9b5eb26ba --- /dev/null +++ b/gen-config.json @@ -0,0 +1 @@ +{ "library": "feign" } \ No newline at end of file diff --git a/modules/swagger-codegen/pom.xml b/modules/swagger-codegen/pom.xml index fc51a41fcdf9..ebdab1e8024a 100644 --- a/modules/swagger-codegen/pom.xml +++ b/modules/swagger-codegen/pom.xml @@ -154,6 +154,7 @@ target/site + @@ -274,7 +276,7 @@ sonatype-snapshots - https://oss.sonatype.org/content/repositories/snapshots + http://oss.sonatype.org/content/repositories/snapshots true diff --git a/pom.xml b/pom.xml index ada3dc0dc4a6..43611eed67d3 100644 --- a/pom.xml +++ b/pom.xml @@ -118,6 +118,7 @@ + maven-compiler-plugin 3.0 @@ -200,7 +202,9 @@ attach-javadocs + jar @@ -536,7 +540,7 @@ sonatype-snapshots - https://oss.sonatype.org/content/repositories/snapshots + http://oss.sonatype.org/content/repositories/snapshots true From ff7d177de38c7a2c867e8467fd0e8e261b03f862 Mon Sep 17 00:00:00 2001 From: David Kiss Date: Mon, 30 Nov 2015 10:21:00 -0500 Subject: [PATCH 09/71] Delete gen-config.json --- gen-config.json | 1 - 1 file changed, 1 deletion(-) delete mode 100644 gen-config.json diff --git a/gen-config.json b/gen-config.json deleted file mode 100644 index 4ec9b5eb26ba..000000000000 --- a/gen-config.json +++ /dev/null @@ -1 +0,0 @@ -{ "library": "feign" } \ No newline at end of file From 83223ae6d0bc3d7b2b1331bfec2728d374e7ecd4 Mon Sep 17 00:00:00 2001 From: 317959997 Date: Mon, 30 Nov 2015 10:25:12 -0500 Subject: [PATCH 10/71] rolling back previous accidental push on changes to pom.xml files --- modules/swagger-codegen/pom.xml | 3 +-- pom.xml | 6 +----- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/modules/swagger-codegen/pom.xml b/modules/swagger-codegen/pom.xml index ebdab1e8024a..0eb6cf027169 100644 --- a/modules/swagger-codegen/pom.xml +++ b/modules/swagger-codegen/pom.xml @@ -154,7 +154,7 @@ target/site - diff --git a/pom.xml b/pom.xml index 43611eed67d3..ada3dc0dc4a6 100644 --- a/pom.xml +++ b/pom.xml @@ -118,7 +118,6 @@ - maven-compiler-plugin 3.0 @@ -202,9 +200,7 @@ attach-javadocs - jar @@ -540,7 +536,7 @@ sonatype-snapshots - http://oss.sonatype.org/content/repositories/snapshots + https://oss.sonatype.org/content/repositories/snapshots true From 44c2751d80e02d9317d0071543850a8d18c0c4b6 Mon Sep 17 00:00:00 2001 From: 317959997 Date: Mon, 30 Nov 2015 10:27:16 -0500 Subject: [PATCH 11/71] added missing files to support JMeter --- .../codegen/languages/JMeterCodegen.java | 183 ++++++++++++++++++ .../main/resources/JMeterCodegen/api.mustache | 28 +++ .../services/io.swagger.codegen.CodegenConfig | 1 + 3 files changed, 212 insertions(+) create mode 100644 modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JMeterCodegen.java create mode 100644 output/swagger-codegen-jmeter/src/main/resources/JMeterCodegen/api.mustache create mode 100644 output/swagger-codegen-jmeter/src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JMeterCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JMeterCodegen.java new file mode 100644 index 000000000000..fb1674772146 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JMeterCodegen.java @@ -0,0 +1,183 @@ +package io.swagger.codegen.languages; + +import io.swagger.codegen.*; +import io.swagger.models.Operation; +import io.swagger.models.Path; +import io.swagger.models.Swagger; +import io.swagger.models.properties.*; +import org.apache.commons.lang.StringUtils; + +import java.util.*; +import java.io.File; + +public class JMeterCodegen extends DefaultCodegen implements CodegenConfig { + + // source folder where to write the files + protected String sourceFolder = ""; + protected String apiVersion = "1.0.0"; + + /** + * Configures the type of generator. + * + * @return the CodegenType for this generator + * @see io.swagger.codegen.CodegenType + */ + public CodegenType getTag() { + return CodegenType.CLIENT; + } + + /** + * Configures a friendly name for the generator. This will be used by the generator + * to select the library with the -l flag. + * + * @return the friendly name for the generator + */ + public String getName() { + return "jmeter"; + } + + /** + * Returns human-friendly help for the generator. Provide the consumer with help + * tips, parameters here + * + * @return A string value for the help message + */ + public String getHelp() { + return "Generates a JMeter .jmx file."; + } + + public JMeterCodegen() { + super(); + + // set the output folder here + outputFolder = "generated-code/JMeterCodegen"; + + /** + * Api classes. You can write classes for each Api file with the apiTemplateFiles map. + * as with models, add multiple entries with different extensions for multiple files per + * class + */ + apiTemplateFiles.put( + "api.mustache", // the template to use + ".jmx"); // the extension for each file to write + + apiTemplateFiles.put("testdata-localhost.mustache", ".csv"); + + /** + * Template Location. This is the location which templates will be read from. The generator + * will use the resource stream to attempt to read the templates. + */ + templateDir = "JMeter"; + + /** + * Api Package. Optional, if needed, this can be used in templates + */ + apiPackage = ""; + + /** + * Model Package. Optional, if needed, this can be used in templates + */ + modelPackage = ""; + + /** + * Reserved words. Override this with reserved words specific to your language + */ + reservedWords = new HashSet ( + Arrays.asList( + "sample1", // replace with static values + "sample2") + ); + + /** + * Additional Properties. These values can be passed to the templates and + * are available in models, apis, and supporting files + */ + additionalProperties.put("apiVersion", apiVersion); + +// supportingFiles.add(new SupportingFile("testdata-localhost.mustache", "input", "testdata-localhost.csv")); + } + + public void preprocessSwagger(Swagger swagger) { + if (swagger != null && swagger.getPaths() != null) { + for (String pathname : swagger.getPaths().keySet()) { + Path path = swagger.getPath(pathname); + if (path.getOperations() != null) { + for (Operation operation : path.getOperations()) { + String pathWithDollars = pathname.replaceAll("\\{", "\\$\\{"); + operation.setVendorExtension("x-path", pathWithDollars); + } + } + } + } + } + + /** + * Escapes a reserved word as defined in the `reservedWords` array. Handle escaping + * those terms here. This logic is only called if a variable matches the reseved words + * + * @return the escaped term + */ + @Override + public String escapeReservedWord(String name) { + return "_" + name; // add an underscore to the name + } + + /** + * Location to write model files. You can use the modelPackage() as defined when the class is + * instantiated + */ + public String modelFileFolder() { + return outputFolder + "/" + sourceFolder + "/" + modelPackage().replace('.', File.separatorChar); + } + + /** + * Location to write api files. You can use the apiPackage() as defined when the class is + * instantiated + */ + @Override + public String apiFileFolder() { + return outputFolder + "/" + sourceFolder + "/" + apiPackage().replace('.', File.separatorChar); + } + + /** + * Optional - type declaration. This is a String which is used by the templates to instantiate your + * types. There is typically special handling for different property types + * + * @return a string value used as the `dataType` field for model templates, `returnType` for api templates + */ + @Override + public String getTypeDeclaration(Property p) { + if(p instanceof ArrayProperty) { + ArrayProperty ap = (ArrayProperty) p; + Property inner = ap.getItems(); + return getSwaggerType(p) + "[" + getTypeDeclaration(inner) + "]"; + } + else if (p instanceof MapProperty) { + MapProperty mp = (MapProperty) p; + Property inner = mp.getAdditionalProperties(); + return getSwaggerType(p) + "[String, " + getTypeDeclaration(inner) + "]"; + } + return super.getTypeDeclaration(p); + } + + /** + * Optional - swagger type conversion. This is used to map swagger types in a `Property` into + * either language specific types via `typeMapping` or into complex models if there is not a mapping. + * + * @return a string value of the type or complex model for this property + * @see io.swagger.models.properties.Property + */ + @Override + public String getSwaggerType(Property p) { + String swaggerType = super.getSwaggerType(p); + String type = null; + if(typeMapping.containsKey(swaggerType)) { + type = typeMapping.get(swaggerType); + if(languageSpecificPrimitives.contains(type)) + return toModelName(type); + } + else + type = swaggerType; + return toModelName(type); + } +} \ No newline at end of file diff --git a/output/swagger-codegen-jmeter/src/main/resources/JMeterCodegen/api.mustache b/output/swagger-codegen-jmeter/src/main/resources/JMeterCodegen/api.mustache new file mode 100644 index 000000000000..9dbc8dd4ba13 --- /dev/null +++ b/output/swagger-codegen-jmeter/src/main/resources/JMeterCodegen/api.mustache @@ -0,0 +1,28 @@ + +# This is a sample api mustache template. It is representing a ficticous +# language and won't be usable or compile to anything without lots of changes. +# Use it as an example. You can access the variables in the generator object +# like such: + +# use the package from the `apiPackage` variable +package: {{package}} + +# operations block +{{#operations}} +classname: {{classname}} + +# loop over each operation in the API: +{{#operation}} + +# each operation has a `nickname`: +nickname: {{nickname}} + +# and parameters: +{{#allParams}} +{{paramName}}: {{dataType}} +{{/allParams}} + +{{/operation}} + +# end of operations block +{{/operations}} \ No newline at end of file diff --git a/output/swagger-codegen-jmeter/src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig b/output/swagger-codegen-jmeter/src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig new file mode 100644 index 000000000000..4ea2512a9e8b --- /dev/null +++ b/output/swagger-codegen-jmeter/src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig @@ -0,0 +1 @@ +com.kaviddiss.codegen.JmetercodegenGenerator \ No newline at end of file From 9cfb1c91db1270f14c5adf16808ba47d9d9983c2 Mon Sep 17 00:00:00 2001 From: 317959997 Date: Mon, 30 Nov 2015 10:31:01 -0500 Subject: [PATCH 12/71] removing references to fork in te main README.md file --- README.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index ba1266e0ef40..333566f6d244 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,6 @@ # Swagger Code Generator - -This is a fork with added support for generating - - - Java client using [Netflix Feign](https://github.com/Netflix/feign). - - [Apache JMeter](http://jmeter.apache.org/) project for testing REST endpoints. +-[![Build Status](https://travis-ci.org/swagger-api/swagger-codegen.png)](https://travis-ci.org/swagger-api/swagger-codegen) +-[![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.swagger/swagger-codegen-project/badge.svg?style=plastic)](https://maven-badges.herokuapp.com/maven-central/io.swagger/swagger-codegen-project) ## Overview This is the swagger codegen project, which allows generation of client libraries automatically from a Swagger-compliant server. From bb4589dca1e82f06ace709bf0040295d3d570b92 Mon Sep 17 00:00:00 2001 From: davidkiss Date: Mon, 30 Nov 2015 10:40:12 -0500 Subject: [PATCH 13/71] cleaned up README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 333566f6d244..4738f114cea8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Swagger Code Generator --[![Build Status](https://travis-ci.org/swagger-api/swagger-codegen.png)](https://travis-ci.org/swagger-api/swagger-codegen) --[![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.swagger/swagger-codegen-project/badge.svg?style=plastic)](https://maven-badges.herokuapp.com/maven-central/io.swagger/swagger-codegen-project) + +[![Build Status](https://travis-ci.org/swagger-api/swagger-codegen.png)](https://travis-ci.org/swagger-api/swagger-codegen) +[![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.swagger/swagger-codegen-project/badge.svg?style=plastic)](https://maven-badges.herokuapp.com/maven-central/io.swagger/swagger-codegen-project) ## Overview This is the swagger codegen project, which allows generation of client libraries automatically from a Swagger-compliant server. From 340e8b367102a1af15f45bffbe1fcec2d9a6615c Mon Sep 17 00:00:00 2001 From: davidkiss Date: Mon, 30 Nov 2015 10:41:44 -0500 Subject: [PATCH 14/71] reverting changes to swagger-codegen pom.xml --- modules/swagger-codegen/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/swagger-codegen/pom.xml b/modules/swagger-codegen/pom.xml index 0eb6cf027169..656223ff42b9 100644 --- a/modules/swagger-codegen/pom.xml +++ b/modules/swagger-codegen/pom.xml @@ -275,7 +275,7 @@ sonatype-snapshots - http://oss.sonatype.org/content/repositories/snapshots + https://oss.sonatype.org/content/repositories/snapshots true From 21e88223431cd5d22db213326942d9838751fbf3 Mon Sep 17 00:00:00 2001 From: David Date: Mon, 30 Nov 2015 10:44:32 -0500 Subject: [PATCH 15/71] cleaned up output folder from repo --- .../main/resources/JMeterCodegen/api.mustache | 28 ------------------- .../services/io.swagger.codegen.CodegenConfig | 1 - 2 files changed, 29 deletions(-) delete mode 100644 output/swagger-codegen-jmeter/src/main/resources/JMeterCodegen/api.mustache delete mode 100644 output/swagger-codegen-jmeter/src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig diff --git a/output/swagger-codegen-jmeter/src/main/resources/JMeterCodegen/api.mustache b/output/swagger-codegen-jmeter/src/main/resources/JMeterCodegen/api.mustache deleted file mode 100644 index 9dbc8dd4ba13..000000000000 --- a/output/swagger-codegen-jmeter/src/main/resources/JMeterCodegen/api.mustache +++ /dev/null @@ -1,28 +0,0 @@ - -# This is a sample api mustache template. It is representing a ficticous -# language and won't be usable or compile to anything without lots of changes. -# Use it as an example. You can access the variables in the generator object -# like such: - -# use the package from the `apiPackage` variable -package: {{package}} - -# operations block -{{#operations}} -classname: {{classname}} - -# loop over each operation in the API: -{{#operation}} - -# each operation has a `nickname`: -nickname: {{nickname}} - -# and parameters: -{{#allParams}} -{{paramName}}: {{dataType}} -{{/allParams}} - -{{/operation}} - -# end of operations block -{{/operations}} \ No newline at end of file diff --git a/output/swagger-codegen-jmeter/src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig b/output/swagger-codegen-jmeter/src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig deleted file mode 100644 index 4ea2512a9e8b..000000000000 --- a/output/swagger-codegen-jmeter/src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig +++ /dev/null @@ -1 +0,0 @@ -com.kaviddiss.codegen.JmetercodegenGenerator \ No newline at end of file From eb0e47461c09e442384a7034bce215525be9279d Mon Sep 17 00:00:00 2001 From: xhh Date: Tue, 1 Dec 2015 16:13:31 +0800 Subject: [PATCH 16/71] Add petstore client sample for Java-feign --- bin/java-petstore-feign.json | 4 + bin/java-petstore-feign.sh | 31 +++ samples/client/petstore/java/feign/README.md | 43 ++++ .../client/petstore/java/feign/build.gradle | 113 +++++++++++ .../petstore/java/feign/gradle.properties | 2 + samples/client/petstore/java/feign/pom.xml | 183 ++++++++++++++++++ .../petstore/java/feign/settings.gradle | 1 + .../java/feign/src/main/AndroidManifest.xml | 3 + .../java/io/swagger/client/ApiClient.java | 86 ++++++++ .../java/io/swagger/client/StringUtil.java | 51 +++++ .../java/io/swagger/client/api/PetApi.java | 120 ++++++++++++ .../java/io/swagger/client/api/StoreApi.java | 66 +++++++ .../java/io/swagger/client/api/UserApi.java | 116 +++++++++++ .../io/swagger/client/model/Category.java | 73 +++++++ .../java/io/swagger/client/model/Order.java | 153 +++++++++++++++ .../java/io/swagger/client/model/Pet.java | 155 +++++++++++++++ .../java/io/swagger/client/model/Tag.java | 73 +++++++ .../java/io/swagger/client/model/User.java | 164 ++++++++++++++++ 18 files changed, 1437 insertions(+) create mode 100644 bin/java-petstore-feign.json create mode 100755 bin/java-petstore-feign.sh create mode 100644 samples/client/petstore/java/feign/README.md create mode 100644 samples/client/petstore/java/feign/build.gradle create mode 100644 samples/client/petstore/java/feign/gradle.properties create mode 100644 samples/client/petstore/java/feign/pom.xml create mode 100644 samples/client/petstore/java/feign/settings.gradle create mode 100644 samples/client/petstore/java/feign/src/main/AndroidManifest.xml create mode 100644 samples/client/petstore/java/feign/src/main/java/io/swagger/client/ApiClient.java create mode 100644 samples/client/petstore/java/feign/src/main/java/io/swagger/client/StringUtil.java create mode 100644 samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/PetApi.java create mode 100644 samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/StoreApi.java create mode 100644 samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/UserApi.java create mode 100644 samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Category.java create mode 100644 samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Order.java create mode 100644 samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Pet.java create mode 100644 samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Tag.java create mode 100644 samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/User.java diff --git a/bin/java-petstore-feign.json b/bin/java-petstore-feign.json new file mode 100644 index 000000000000..5502ee3bbad2 --- /dev/null +++ b/bin/java-petstore-feign.json @@ -0,0 +1,4 @@ +{ + "library": "feign", + "artifactId": "swagger-petstore-feign" +} diff --git a/bin/java-petstore-feign.sh b/bin/java-petstore-feign.sh new file mode 100755 index 000000000000..6f0a5fdf8ff5 --- /dev/null +++ b/bin/java-petstore-feign.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +SCRIPT="$0" + +while [ -h "$SCRIPT" ] ; do + ls=`ls -ld "$SCRIPT"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + SCRIPT="$link" + else + SCRIPT=`dirname "$SCRIPT"`/"$link" + fi +done + +if [ ! -d "${APP_DIR}" ]; then + APP_DIR=`dirname "$SCRIPT"`/.. + APP_DIR=`cd "${APP_DIR}"; pwd` +fi + +executable="./modules/swagger-codegen-cli/target/swagger-codegen-cli.jar" + +if [ ! -f "$executable" ] +then + mvn clean package +fi + +# if you've executed sbt assembly previously it will use that instead. +export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties" +ags="$@ generate -i modules/swagger-codegen/src/test/resources/2_0/petstore.json -l java -c bin/java-petstore-feign.json -o samples/client/petstore/java/feign" + +java $JAVA_OPTS -jar $executable $ags diff --git a/samples/client/petstore/java/feign/README.md b/samples/client/petstore/java/feign/README.md new file mode 100644 index 000000000000..3ca7abfb5573 --- /dev/null +++ b/samples/client/petstore/java/feign/README.md @@ -0,0 +1,43 @@ +# swagger-petstore-feign + +## Requirements + +Building the API client library requires [Maven](https://maven.apache.org/) to be installed. + +## Installation & Usage + +To install the API client library to your local Maven repository, simply execute: + +```shell +mvn install +``` + +To deploy it to a remote Maven repository instead, configure the settings of the repository and execute: + +```shell +mvn deploy +``` + +Refer to the [official documentation](https://maven.apache.org/plugins/maven-deploy-plugin/usage.html) for more information. + +After the client libarary is installed/deployed, you can use it in your Maven project by adding the following to your *pom.xml*: + +```xml + + io.swagger + swagger-petstore-feign + 1.0.0 + compile + + +``` + +## Recommendation + +It's recommended to create an instance of `ApiClient` per thread in a multithreaded environment to avoid any potential issue. + +## Author + +apiteam@swagger.io + + diff --git a/samples/client/petstore/java/feign/build.gradle b/samples/client/petstore/java/feign/build.gradle new file mode 100644 index 000000000000..0bfcfbec71f2 --- /dev/null +++ b/samples/client/petstore/java/feign/build.gradle @@ -0,0 +1,113 @@ +group = 'io.swagger' +version = '1.0.0' + +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.2.2' + classpath 'com.github.dcendents:android-maven-plugin:1.2' + } +} + +repositories { + jcenter() +} + + +if(hasProperty('target') && target == 'android') { + + apply plugin: 'com.android.library' + apply plugin: 'com.github.dcendents.android-maven' + + android { + compileSdkVersion 22 + buildToolsVersion '22.0.0' + defaultConfig { + minSdkVersion 14 + targetSdkVersion 22 + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_7 + targetCompatibility JavaVersion.VERSION_1_7 + } + + // Rename the aar correctly + libraryVariants.all { variant -> + variant.outputs.each { output -> + def outputFile = output.outputFile + if (outputFile != null && outputFile.name.endsWith('.aar')) { + def fileName = "${project.name}-${variant.baseName}-${version}.aar" + output.outputFile = new File(outputFile.parent, fileName) + } + } + } + + dependencies { + provided 'javax.annotation:jsr250-api:1.0' + } + } + + afterEvaluate { + android.libraryVariants.all { variant -> + def task = project.tasks.create "jar${variant.name.capitalize()}", Jar + task.description = "Create jar artifact for ${variant.name}" + task.dependsOn variant.javaCompile + task.from variant.javaCompile.destinationDir + task.destinationDir = project.file("${project.buildDir}/outputs/jar") + task.archiveName = "${project.name}-${variant.baseName}-${version}.jar" + artifacts.add('archives', task); + } + } + + task sourcesJar(type: Jar) { + from android.sourceSets.main.java.srcDirs + classifier = 'sources' + } + + artifacts { + archives sourcesJar + } + +} else { + + apply plugin: 'java' + apply plugin: 'maven' + + sourceCompatibility = JavaVersion.VERSION_1_7 + targetCompatibility = JavaVersion.VERSION_1_7 + + install { + repositories.mavenInstaller { + pom.artifactId = 'swagger-petstore-feign' + } + } + + task execute(type:JavaExec) { + main = System.getProperty('mainClass') + classpath = sourceSets.main.runtimeClasspath + } +} + +ext { + swagger_annotations_version = "1.5.0" + jackson_version = "2.6.3" + feign_version = "8.1.1" + jodatime_version = "2.5" + junit_version = "4.12" +} + +dependencies { + compile "io.swagger:swagger-annotations:$swagger_annotations_version" + compile "com.netflix.feign:feign-core:$feign_version" + compile "com.netflix.feign:feign-jackson:$feign_version" + compile "com.netflix.feign:feign-slf4j:$feign_version" + compile "com.fasterxml.jackson.core:jackson-core:$jackson_version" + compile "com.fasterxml.jackson.core:jackson-annotations:$jackson_version" + compile "com.fasterxml.jackson.core:jackson-databind:$jackson_version" + compile "com.fasterxml.jackson.datatype:jackson-datatype-joda:2.1.5" + compile "joda-time:joda-time:$jodatime_version" + compile "com.brsanthu:migbase64:2.2" + testCompile "junit:junit:$junit_version" +} diff --git a/samples/client/petstore/java/feign/gradle.properties b/samples/client/petstore/java/feign/gradle.properties new file mode 100644 index 000000000000..05644f0754af --- /dev/null +++ b/samples/client/petstore/java/feign/gradle.properties @@ -0,0 +1,2 @@ +# Uncomment to build for Android +#target = android \ No newline at end of file diff --git a/samples/client/petstore/java/feign/pom.xml b/samples/client/petstore/java/feign/pom.xml new file mode 100644 index 000000000000..5f7e95518625 --- /dev/null +++ b/samples/client/petstore/java/feign/pom.xml @@ -0,0 +1,183 @@ + + 4.0.0 + io.swagger + swagger-petstore-feign + jar + swagger-petstore-feign + 1.0.0 + + scm:git:git@github.com:swagger-api/swagger-mustache.git + scm:git:git@github.com:swagger-api/swagger-codegen.git + https://github.com/swagger-api/swagger-codegen + + + 2.2.0 + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.12 + + + + loggerPath + conf/log4j.properties + + + -Xms512m -Xmx1500m + methods + pertest + + + + maven-dependency-plugin + + + package + + copy-dependencies + + + ${project.build.directory}/lib + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.2 + + + + jar + test-jar + + + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + add_sources + generate-sources + + add-source + + + + src/main/java + + + + + add_test_sources + generate-test-sources + + add-test-source + + + + src/test/java + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.6 + 1.6 + + + + + + + io.swagger + swagger-annotations + ${swagger-annotations-version} + + + + + com.netflix.feign + feign-core + ${feign-version} + + + com.netflix.feign + feign-jackson + ${feign-version} + + + com.netflix.feign + feign-slf4j + ${feign-version} + + + + + com.fasterxml.jackson.core + jackson-core + ${jackson-version} + + + com.fasterxml.jackson.core + jackson-annotations + ${jackson-version} + + + com.fasterxml.jackson.core + jackson-databind + ${jackson-version} + + + com.fasterxml.jackson.datatype + jackson-datatype-joda + 2.1.5 + + + joda-time + joda-time + ${jodatime-version} + + + + + com.brsanthu + migbase64 + 2.2 + + + + + junit + junit + ${junit-version} + test + + + + 1.5.0 + 8.1.1 + 2.6.3 + 2.5 + 4.12 + 1.0.0 + + diff --git a/samples/client/petstore/java/feign/settings.gradle b/samples/client/petstore/java/feign/settings.gradle new file mode 100644 index 000000000000..a25109c126eb --- /dev/null +++ b/samples/client/petstore/java/feign/settings.gradle @@ -0,0 +1 @@ +rootProject.name = "swagger-petstore-feign" \ No newline at end of file diff --git a/samples/client/petstore/java/feign/src/main/AndroidManifest.xml b/samples/client/petstore/java/feign/src/main/AndroidManifest.xml new file mode 100644 index 000000000000..465dcb520c40 --- /dev/null +++ b/samples/client/petstore/java/feign/src/main/AndroidManifest.xml @@ -0,0 +1,3 @@ + + + diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/ApiClient.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/ApiClient.java new file mode 100644 index 000000000000..02f5b7fb982c --- /dev/null +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/ApiClient.java @@ -0,0 +1,86 @@ +package io.swagger.client; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import feign.Feign; +import feign.jackson.JacksonDecoder; +import feign.jackson.JacksonEncoder; +import feign.slf4j.Slf4jLogger; + +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-01T16:10:23.565+08:00") +public class ApiClient { + public interface Api {} + + private ObjectMapper objectMapper; + private String basePath = "http://petstore.swagger.io/v2"; + + public ApiClient() { + objectMapper = createObjectMapper(); + } + + public String getBasePath() { + return basePath; + } + + public ApiClient setBasePath(String basePath) { + this.basePath = basePath; + return this; + } + + private ObjectMapper createObjectMapper() { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING); + objectMapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING); + return objectMapper; + } + + /** + * Creates a feign client for given API interface. + * + * Usage: + * ApiClient apiClient = new ApiClient(); + * apiClient.setBasePath("http://localhost:8080"); + * XYZApi api = apiClient.buildClient(XYZApi.class); + * XYZResponse response = api.someMethod(...); + */ + public T buildClient(Class clientClass) { + return Feign.builder() + .encoder(new JacksonEncoder(objectMapper)) + .decoder(new JacksonDecoder(objectMapper)) +// enable for basic auth: +// .requestInterceptor(new feign.auth.BasicAuthRequestInterceptor(username, password)) + .logger(new Slf4jLogger()) + .target(clientClass, basePath); + } + + /** + * Select the Accept header's value from the given accepts array: + * if JSON exists in the given array, use it; + * otherwise use all of them (joining into a string) + * + * @param accepts The accepts array to select from + * @return The Accept header to use. If the given array is empty, + * null will be returned (not to set the Accept header explicitly). + */ + public String selectHeaderAccept(String[] accepts) { + if (accepts.length == 0) return null; + if (StringUtil.containsIgnoreCase(accepts, "application/json")) return "application/json"; + return StringUtil.join(accepts, ","); + } + + /** + * Select the Content-Type header's value from the given array: + * if JSON exists in the given array, use it; + * otherwise use the first one of the array. + * + * @param contentTypes The Content-Type array to select from + * @return The Content-Type header to use. If the given array is empty, + * JSON will be used. + */ + public String selectHeaderContentType(String[] contentTypes) { + if (contentTypes.length == 0) return "application/json"; + if (StringUtil.containsIgnoreCase(contentTypes, "application/json")) return "application/json"; + return contentTypes[0]; + } +} diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/StringUtil.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/StringUtil.java new file mode 100644 index 000000000000..82b8d8afa0bf --- /dev/null +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/StringUtil.java @@ -0,0 +1,51 @@ +package io.swagger.client; + +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-01T16:10:23.565+08:00") +public class StringUtil { + /** + * Check if the given array contains the given value (with case-insensitive comparison). + * + * @param array The array + * @param value The value to search + * @return true if the array contains the value + */ + public static boolean containsIgnoreCase(String[] array, String value) { + for (String str : array) { + if (value == null && str == null) return true; + if (value != null && value.equalsIgnoreCase(str)) return true; + } + return false; + } + + /** + * Join an array of strings with the given separator. + *

+ * Note: This might be replaced by utility method from commons-lang or guava someday + * if one of those libraries is added as dependency. + *

+ * + * @param array The array of strings + * @param separator The separator + * @return the resulting string + */ + public static String join(String[] array, String separator) { + int len = array.length; + if (len == 0) return ""; + + StringBuilder out = new StringBuilder(); + out.append(array[0]); + for (int i = 1; i < len; i++) { + out.append(separator).append(array[i]); + } + return out.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + public static String toIndentedString(Object o) { + if (o == null) return "null"; + return o.toString().replace("\n", "\n "); + } +} diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/PetApi.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/PetApi.java new file mode 100644 index 000000000000..54213294eed5 --- /dev/null +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/PetApi.java @@ -0,0 +1,120 @@ +package io.swagger.client.api; + +import io.swagger.client.ApiException; +import io.swagger.client.ApiClient; +import io.swagger.client.Configuration; +import io.swagger.client.Pair; +import io.swagger.client.TypeRef; + +import io.swagger.client.model.Pet; +import java.io.File; + +import java.util.*; +import feign.*; + +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-01T16:10:23.565+08:00") +public interface PetApi extends io.swagger.client.ApiClient.Api { + + + /** + * Update an existing pet + * + * @param body Pet object that needs to be added to the store + * @return void + */ + @RequestLine("PUT /pet") + @Headers({ + + }) + void updatePet (@Param("body") Pet body) throws ApiException; + + /** + * Add a new pet to the store + * + * @param body Pet object that needs to be added to the store + * @return void + */ + @RequestLine("POST /pet") + @Headers({ + + }) + void addPet (@Param("body") Pet body) throws ApiException; + + /** + * Finds Pets by status + * Multiple status values can be provided with comma seperated strings + * @param status Status values that need to be considered for filter + * @return List + */ + @RequestLine("GET /pet/findByStatus?status={status}") + @Headers({ + + }) + List findPetsByStatus (@Param("status") List status) throws ApiException; + + /** + * Finds Pets by tags + * Muliple tags can be provided with comma seperated strings. Use tag1, tag2, tag3 for testing. + * @param tags Tags to filter by + * @return List + */ + @RequestLine("GET /pet/findByTags?tags={tags}") + @Headers({ + + }) + List findPetsByTags (@Param("tags") List tags) throws ApiException; + + /** + * Find pet by ID + * Returns a pet when ID < 10. ID > 10 or nonintegers will simulate API error conditions + * @param petId ID of pet that needs to be fetched + * @return Pet + */ + @RequestLine("GET /pet/{petId}") + @Headers({ + + }) + Pet getPetById (@Param("petId") Long petId) throws ApiException; + + /** + * Updates a pet in the store with form data + * + * @param petId ID of pet that needs to be updated + * @param name Updated name of the pet + * @param status Updated status of the pet + * @return void + */ + @RequestLine("POST /pet/{petId}") + @Headers({ + + }) + void updatePetWithForm (@Param("petId") String petId, @Param("name") String name, @Param("status") String status) throws ApiException; + + /** + * Deletes a pet + * + * @param petId Pet id to delete + * @param apiKey + * @return void + */ + @RequestLine("DELETE /pet/{petId}") + @Headers({ + "apiKey: {apiKey}" + }) + void deletePet (@Param("petId") Long petId, @Param("apiKey") String apiKey) throws ApiException; + + /** + * uploads an image + * + * @param petId ID of pet to update + * @param additionalMetadata Additional data to pass to server + * @param file file to upload + * @return void + */ + @RequestLine("POST /pet/{petId}/uploadImage") + @Headers({ + + }) + void uploadFile (@Param("petId") Long petId, @Param("additionalMetadata") String additionalMetadata, @Param("file") File file) throws ApiException; + +} diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/StoreApi.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/StoreApi.java new file mode 100644 index 000000000000..c35f8578eebb --- /dev/null +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/StoreApi.java @@ -0,0 +1,66 @@ +package io.swagger.client.api; + +import io.swagger.client.ApiException; +import io.swagger.client.ApiClient; +import io.swagger.client.Configuration; +import io.swagger.client.Pair; +import io.swagger.client.TypeRef; + +import java.util.Map; +import io.swagger.client.model.Order; + +import java.util.*; +import feign.*; + +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-01T16:10:23.565+08:00") +public interface StoreApi extends io.swagger.client.ApiClient.Api { + + + /** + * Returns pet inventories by status + * Returns a map of status codes to quantities + * @return Map + */ + @RequestLine("GET /store/inventory") + @Headers({ + + }) + Map getInventory () throws ApiException; + + /** + * Place an order for a pet + * + * @param body order placed for purchasing the pet + * @return Order + */ + @RequestLine("POST /store/order") + @Headers({ + + }) + Order placeOrder (@Param("body") Order body) throws ApiException; + + /** + * Find purchase order by ID + * For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions + * @param orderId ID of pet that needs to be fetched + * @return Order + */ + @RequestLine("GET /store/order/{orderId}") + @Headers({ + + }) + Order getOrderById (@Param("orderId") String orderId) throws ApiException; + + /** + * Delete purchase order by ID + * For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors + * @param orderId ID of the order that needs to be deleted + * @return void + */ + @RequestLine("DELETE /store/order/{orderId}") + @Headers({ + + }) + void deleteOrder (@Param("orderId") String orderId) throws ApiException; + +} diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/UserApi.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/UserApi.java new file mode 100644 index 000000000000..ed567bc16f2e --- /dev/null +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/UserApi.java @@ -0,0 +1,116 @@ +package io.swagger.client.api; + +import io.swagger.client.ApiException; +import io.swagger.client.ApiClient; +import io.swagger.client.Configuration; +import io.swagger.client.Pair; +import io.swagger.client.TypeRef; + +import io.swagger.client.model.User; +import java.util.*; + +import java.util.*; +import feign.*; + +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-01T16:10:23.565+08:00") +public interface UserApi extends io.swagger.client.ApiClient.Api { + + + /** + * Create user + * This can only be done by the logged in user. + * @param body Created user object + * @return void + */ + @RequestLine("POST /user") + @Headers({ + + }) + void createUser (@Param("body") User body) throws ApiException; + + /** + * Creates list of users with given input array + * + * @param body List of user object + * @return void + */ + @RequestLine("POST /user/createWithArray") + @Headers({ + + }) + void createUsersWithArrayInput (@Param("body") List body) throws ApiException; + + /** + * Creates list of users with given input array + * + * @param body List of user object + * @return void + */ + @RequestLine("POST /user/createWithList") + @Headers({ + + }) + void createUsersWithListInput (@Param("body") List body) throws ApiException; + + /** + * Logs user into the system + * + * @param username The user name for login + * @param password The password for login in clear text + * @return String + */ + @RequestLine("GET /user/login?username={username}&password={password}") + @Headers({ + + }) + String loginUser (@Param("username") String username, @Param("password") String password) throws ApiException; + + /** + * Logs out current logged in user session + * + * @return void + */ + @RequestLine("GET /user/logout") + @Headers({ + + }) + void logoutUser () throws ApiException; + + /** + * Get user by user name + * + * @param username The name that needs to be fetched. Use user1 for testing. + * @return User + */ + @RequestLine("GET /user/{username}") + @Headers({ + + }) + User getUserByName (@Param("username") String username) throws ApiException; + + /** + * Updated user + * This can only be done by the logged in user. + * @param username name that need to be deleted + * @param body Updated user object + * @return void + */ + @RequestLine("PUT /user/{username}") + @Headers({ + + }) + void updateUser (@Param("username") String username, @Param("body") User body) throws ApiException; + + /** + * Delete user + * This can only be done by the logged in user. + * @param username The name that needs to be deleted + * @return void + */ + @RequestLine("DELETE /user/{username}") + @Headers({ + + }) + void deleteUser (@Param("username") String username) throws ApiException; + +} diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Category.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Category.java new file mode 100644 index 000000000000..e76088313009 --- /dev/null +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Category.java @@ -0,0 +1,73 @@ +package io.swagger.client.model; + +import io.swagger.client.StringUtil; + + +import java.util.Objects; + +import io.swagger.annotations.*; +import com.fasterxml.jackson.annotation.JsonProperty; + + +@ApiModel(description = "") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-01T16:10:23.565+08:00") +public class Category { + + private Long id = null; + private String name = null; + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("id") + public Long getId() { + return id; + } + public void setId(Long id) { + this.id = id; + } + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("name") + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Category category = (Category) o; + return Objects.equals(id, category.id) && + Objects.equals(name, category.name); + } + + @Override + public int hashCode() { + return Objects.hash(id, name); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Category {\n"); + + sb.append(" id: ").append(StringUtil.toIndentedString(id)).append("\n"); + sb.append(" name: ").append(StringUtil.toIndentedString(name)).append("\n"); + sb.append("}"); + return sb.toString(); + } +} diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Order.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Order.java new file mode 100644 index 000000000000..4b6337b44cc4 --- /dev/null +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Order.java @@ -0,0 +1,153 @@ +package io.swagger.client.model; + +import io.swagger.client.StringUtil; +import java.util.Date; + + +import java.util.Objects; + +import io.swagger.annotations.*; +import com.fasterxml.jackson.annotation.JsonProperty; + + +@ApiModel(description = "") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-01T16:10:23.565+08:00") +public class Order { + + private Long id = null; + private Long petId = null; + private Integer quantity = null; + private Date shipDate = null; + +public enum StatusEnum { + PLACED("placed"), + APPROVED("approved"), + DELIVERED("delivered"); + + private String value; + + StatusEnum(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } +} + + private StatusEnum status = null; + private Boolean complete = null; + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("id") + public Long getId() { + return id; + } + public void setId(Long id) { + this.id = id; + } + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("petId") + public Long getPetId() { + return petId; + } + public void setPetId(Long petId) { + this.petId = petId; + } + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("quantity") + public Integer getQuantity() { + return quantity; + } + public void setQuantity(Integer quantity) { + this.quantity = quantity; + } + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("shipDate") + public Date getShipDate() { + return shipDate; + } + public void setShipDate(Date shipDate) { + this.shipDate = shipDate; + } + + + /** + * Order Status + **/ + @ApiModelProperty(value = "Order Status") + @JsonProperty("status") + public StatusEnum getStatus() { + return status; + } + public void setStatus(StatusEnum status) { + this.status = status; + } + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("complete") + public Boolean getComplete() { + return complete; + } + public void setComplete(Boolean complete) { + this.complete = complete; + } + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Order order = (Order) o; + return Objects.equals(id, order.id) && + Objects.equals(petId, order.petId) && + Objects.equals(quantity, order.quantity) && + Objects.equals(shipDate, order.shipDate) && + Objects.equals(status, order.status) && + Objects.equals(complete, order.complete); + } + + @Override + public int hashCode() { + return Objects.hash(id, petId, quantity, shipDate, status, complete); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Order {\n"); + + sb.append(" id: ").append(StringUtil.toIndentedString(id)).append("\n"); + sb.append(" petId: ").append(StringUtil.toIndentedString(petId)).append("\n"); + sb.append(" quantity: ").append(StringUtil.toIndentedString(quantity)).append("\n"); + sb.append(" shipDate: ").append(StringUtil.toIndentedString(shipDate)).append("\n"); + sb.append(" status: ").append(StringUtil.toIndentedString(status)).append("\n"); + sb.append(" complete: ").append(StringUtil.toIndentedString(complete)).append("\n"); + sb.append("}"); + return sb.toString(); + } +} diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Pet.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Pet.java new file mode 100644 index 000000000000..a3d8218282fe --- /dev/null +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Pet.java @@ -0,0 +1,155 @@ +package io.swagger.client.model; + +import io.swagger.client.StringUtil; +import io.swagger.client.model.Category; +import java.util.*; +import io.swagger.client.model.Tag; + + +import java.util.Objects; + +import io.swagger.annotations.*; +import com.fasterxml.jackson.annotation.JsonProperty; + + +@ApiModel(description = "") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-01T16:10:23.565+08:00") +public class Pet { + + private Long id = null; + private Category category = null; + private String name = null; + private List photoUrls = new ArrayList(); + private List tags = new ArrayList(); + +public enum StatusEnum { + AVAILABLE("available"), + PENDING("pending"), + SOLD("sold"); + + private String value; + + StatusEnum(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } +} + + private StatusEnum status = null; + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("id") + public Long getId() { + return id; + } + public void setId(Long id) { + this.id = id; + } + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("category") + public Category getCategory() { + return category; + } + public void setCategory(Category category) { + this.category = category; + } + + + /** + **/ + @ApiModelProperty(required = true, value = "") + @JsonProperty("name") + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + + + /** + **/ + @ApiModelProperty(required = true, value = "") + @JsonProperty("photoUrls") + public List getPhotoUrls() { + return photoUrls; + } + public void setPhotoUrls(List photoUrls) { + this.photoUrls = photoUrls; + } + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("tags") + public List getTags() { + return tags; + } + public void setTags(List tags) { + this.tags = tags; + } + + + /** + * pet status in the store + **/ + @ApiModelProperty(value = "pet status in the store") + @JsonProperty("status") + public StatusEnum getStatus() { + return status; + } + public void setStatus(StatusEnum status) { + this.status = status; + } + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Pet pet = (Pet) o; + return Objects.equals(id, pet.id) && + Objects.equals(category, pet.category) && + Objects.equals(name, pet.name) && + Objects.equals(photoUrls, pet.photoUrls) && + Objects.equals(tags, pet.tags) && + Objects.equals(status, pet.status); + } + + @Override + public int hashCode() { + return Objects.hash(id, category, name, photoUrls, tags, status); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Pet {\n"); + + sb.append(" id: ").append(StringUtil.toIndentedString(id)).append("\n"); + sb.append(" category: ").append(StringUtil.toIndentedString(category)).append("\n"); + sb.append(" name: ").append(StringUtil.toIndentedString(name)).append("\n"); + sb.append(" photoUrls: ").append(StringUtil.toIndentedString(photoUrls)).append("\n"); + sb.append(" tags: ").append(StringUtil.toIndentedString(tags)).append("\n"); + sb.append(" status: ").append(StringUtil.toIndentedString(status)).append("\n"); + sb.append("}"); + return sb.toString(); + } +} diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Tag.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Tag.java new file mode 100644 index 000000000000..92049ae02dc8 --- /dev/null +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Tag.java @@ -0,0 +1,73 @@ +package io.swagger.client.model; + +import io.swagger.client.StringUtil; + + +import java.util.Objects; + +import io.swagger.annotations.*; +import com.fasterxml.jackson.annotation.JsonProperty; + + +@ApiModel(description = "") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-01T16:10:23.565+08:00") +public class Tag { + + private Long id = null; + private String name = null; + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("id") + public Long getId() { + return id; + } + public void setId(Long id) { + this.id = id; + } + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("name") + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Tag tag = (Tag) o; + return Objects.equals(id, tag.id) && + Objects.equals(name, tag.name); + } + + @Override + public int hashCode() { + return Objects.hash(id, name); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Tag {\n"); + + sb.append(" id: ").append(StringUtil.toIndentedString(id)).append("\n"); + sb.append(" name: ").append(StringUtil.toIndentedString(name)).append("\n"); + sb.append("}"); + return sb.toString(); + } +} diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/User.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/User.java new file mode 100644 index 000000000000..72cb300602c1 --- /dev/null +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/User.java @@ -0,0 +1,164 @@ +package io.swagger.client.model; + +import io.swagger.client.StringUtil; + + +import java.util.Objects; + +import io.swagger.annotations.*; +import com.fasterxml.jackson.annotation.JsonProperty; + + +@ApiModel(description = "") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-01T16:10:23.565+08:00") +public class User { + + private Long id = null; + private String username = null; + private String firstName = null; + private String lastName = null; + private String email = null; + private String password = null; + private String phone = null; + private Integer userStatus = null; + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("id") + public Long getId() { + return id; + } + public void setId(Long id) { + this.id = id; + } + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("username") + public String getUsername() { + return username; + } + public void setUsername(String username) { + this.username = username; + } + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("firstName") + public String getFirstName() { + return firstName; + } + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("lastName") + public String getLastName() { + return lastName; + } + public void setLastName(String lastName) { + this.lastName = lastName; + } + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("email") + public String getEmail() { + return email; + } + public void setEmail(String email) { + this.email = email; + } + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("password") + public String getPassword() { + return password; + } + public void setPassword(String password) { + this.password = password; + } + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("phone") + public String getPhone() { + return phone; + } + public void setPhone(String phone) { + this.phone = phone; + } + + + /** + * User Status + **/ + @ApiModelProperty(value = "User Status") + @JsonProperty("userStatus") + public Integer getUserStatus() { + return userStatus; + } + public void setUserStatus(Integer userStatus) { + this.userStatus = userStatus; + } + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + User user = (User) o; + return Objects.equals(id, user.id) && + Objects.equals(username, user.username) && + Objects.equals(firstName, user.firstName) && + Objects.equals(lastName, user.lastName) && + Objects.equals(email, user.email) && + Objects.equals(password, user.password) && + Objects.equals(phone, user.phone) && + Objects.equals(userStatus, user.userStatus); + } + + @Override + public int hashCode() { + return Objects.hash(id, username, firstName, lastName, email, password, phone, userStatus); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class User {\n"); + + sb.append(" id: ").append(StringUtil.toIndentedString(id)).append("\n"); + sb.append(" username: ").append(StringUtil.toIndentedString(username)).append("\n"); + sb.append(" firstName: ").append(StringUtil.toIndentedString(firstName)).append("\n"); + sb.append(" lastName: ").append(StringUtil.toIndentedString(lastName)).append("\n"); + sb.append(" email: ").append(StringUtil.toIndentedString(email)).append("\n"); + sb.append(" password: ").append(StringUtil.toIndentedString(password)).append("\n"); + sb.append(" phone: ").append(StringUtil.toIndentedString(phone)).append("\n"); + sb.append(" userStatus: ").append(StringUtil.toIndentedString(userStatus)).append("\n"); + sb.append("}"); + return sb.toString(); + } +} From eb4acd097150e8ba991fc4116d7a6b5a86da6163 Mon Sep 17 00:00:00 2001 From: David Kiss Date: Mon, 7 Dec 2015 01:13:20 -0500 Subject: [PATCH 17/71] added unit tests to feign client --- config-feign.json | 1 + .../codegen/languages/JavaClientCodegen.java | 62 +++++- .../Java/libraries/feign/ApiClient.mustache | 2 +- .../libraries/feign/FormAwareEncoder.mustache | 159 ++++++++++++++ .../Java/libraries/feign/api.mustache | 6 +- samples/client/petstore/java/feign/README.md | 43 ++++ .../client/petstore/java/feign/build.gradle | 113 ++++++++++ .../petstore/java/feign/gradle.properties | 2 + samples/client/petstore/java/feign/pom.xml | 183 ++++++++++++++++ .../petstore/java/feign/settings.gradle | 1 + .../java/io/swagger/client/ApiClient.java | 86 ++++++++ .../io/swagger/client/FormAwareEncoder.java | 159 ++++++++++++++ .../java/io/swagger/client/StringUtil.java | 51 +++++ .../java/io/swagger/client/api/PetApi.java | 133 ++++++++++++ .../java/io/swagger/client/api/StoreApi.java | 73 +++++++ .../java/io/swagger/client/api/UserApi.java | 127 +++++++++++ .../io/swagger/client/model/ApiResponse.java | 92 ++++++++ .../io/swagger/client/model/Category.java | 77 +++++++ .../java/io/swagger/client/model/Order.java | 157 ++++++++++++++ .../java/io/swagger/client/model/Pet.java | 159 ++++++++++++++ .../java/io/swagger/client/model/Tag.java | 77 +++++++ .../java/io/swagger/client/model/User.java | 168 +++++++++++++++ .../io/swagger/client/StringUtilTest.java | 32 +++ .../io/swagger/petstore/test/PetApiTest.java | 199 ++++++++++++++++++ .../swagger/petstore/test/StoreApiTest.java | 70 ++++++ .../io/swagger/petstore/test/UserApiTest.java | 85 ++++++++ 26 files changed, 2313 insertions(+), 4 deletions(-) create mode 100644 config-feign.json create mode 100644 modules/swagger-codegen/src/main/resources/Java/libraries/feign/FormAwareEncoder.mustache create mode 100644 samples/client/petstore/java/feign/README.md create mode 100644 samples/client/petstore/java/feign/build.gradle create mode 100644 samples/client/petstore/java/feign/gradle.properties create mode 100644 samples/client/petstore/java/feign/pom.xml create mode 100644 samples/client/petstore/java/feign/settings.gradle create mode 100644 samples/client/petstore/java/feign/src/main/java/io/swagger/client/ApiClient.java create mode 100644 samples/client/petstore/java/feign/src/main/java/io/swagger/client/FormAwareEncoder.java create mode 100644 samples/client/petstore/java/feign/src/main/java/io/swagger/client/StringUtil.java create mode 100644 samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/PetApi.java create mode 100644 samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/StoreApi.java create mode 100644 samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/UserApi.java create mode 100644 samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/ApiResponse.java create mode 100644 samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Category.java create mode 100644 samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Order.java create mode 100644 samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Pet.java create mode 100644 samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Tag.java create mode 100644 samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/User.java create mode 100644 samples/client/petstore/java/feign/src/test/java/io/swagger/client/StringUtilTest.java create mode 100644 samples/client/petstore/java/feign/src/test/java/io/swagger/petstore/test/PetApiTest.java create mode 100644 samples/client/petstore/java/feign/src/test/java/io/swagger/petstore/test/StoreApiTest.java create mode 100644 samples/client/petstore/java/feign/src/test/java/io/swagger/petstore/test/UserApiTest.java diff --git a/config-feign.json b/config-feign.json new file mode 100644 index 000000000000..3b8c48c3caa0 --- /dev/null +++ b/config-feign.json @@ -0,0 +1 @@ +{"library":"feign"} \ No newline at end of file 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 1c2ccf2d6900..b12894a73003 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 @@ -11,6 +11,12 @@ import io.swagger.codegen.CodegenType; import io.swagger.codegen.DefaultCodegen; import io.swagger.codegen.SupportingFile; import io.swagger.models.Model; +import io.swagger.models.Operation; +import io.swagger.models.Path; +import io.swagger.models.Swagger; +import io.swagger.models.parameters.BodyParameter; +import io.swagger.models.parameters.FormParameter; +import io.swagger.models.parameters.Parameter; import io.swagger.models.properties.ArrayProperty; import io.swagger.models.properties.BooleanProperty; import io.swagger.models.properties.DoubleProperty; @@ -216,7 +222,9 @@ public class JavaClientCodegen extends DefaultCodegen implements CodegenConfig { supportingFiles.add(new SupportingFile("StringUtil.mustache", invokerFolder, "StringUtil.java")); final String authFolder = (sourceFolder + '/' + invokerPackage + ".auth").replace(".", "/"); - if (!"feign".equals(getLibrary())) { + if ("feign".equals(getLibrary())) { + supportingFiles.add(new SupportingFile("FormAwareEncoder.mustache", invokerFolder, "FormAwareEncoder.java")); + } else { supportingFiles.add(new SupportingFile("auth/HttpBasicAuth.mustache", authFolder, "HttpBasicAuth.java")); supportingFiles.add(new SupportingFile("auth/ApiKeyAuth.mustache", authFolder, "ApiKeyAuth.java")); supportingFiles.add(new SupportingFile("auth/OAuth.mustache", authFolder, "OAuth.java")); @@ -544,6 +552,58 @@ public class JavaClientCodegen extends DefaultCodegen implements CodegenConfig { return objs; } + public void preprocessSwagger(Swagger swagger) { + if (swagger != null && swagger.getPaths() != null) { + for (String pathname : swagger.getPaths().keySet()) { + Path path = swagger.getPath(pathname); + if (path.getOperations() != null) { + for (Operation operation : path.getOperations()) { + boolean hasFormParameters = false; + for (Parameter parameter : operation.getParameters()) { + parameter.getVendorExtensions().put("x-isBody", parameter instanceof BodyParameter); + if (parameter instanceof FormParameter) { + hasFormParameters = true; + } + } + + String defaultContentType = hasFormParameters ? "application/x-www-form-urlencoded" : "application/json"; + String contentType = operation.getConsumes() == null || operation.getConsumes().isEmpty() + ? defaultContentType : operation.getConsumes().get(0); + String accepts = getAccept(operation); + operation.setVendorExtension("x-contentType", contentType); + operation.setVendorExtension("x-accepts", accepts); + } + } + } + } + } + + private String getAccept(Operation operation) { + String accepts = null; + String defaultContentType = "application/json"; + if (operation.getProduces() != null && !operation.getProduces().isEmpty()) { + StringBuilder sb = new StringBuilder(); + for (String produces : operation.getProduces()) { + if (defaultContentType.equalsIgnoreCase(produces)) { + accepts = defaultContentType; + break; + } else { + if (sb.length() > 0) { + sb.append(","); + } + sb.append(produces); + } + } + if (accepts == null) { + accepts = sb.toString(); + } + } else { + accepts = defaultContentType; + } + + return accepts; + } + protected boolean needToImport(String type) { return super.needToImport(type) && type.indexOf(".") < 0; } diff --git a/modules/swagger-codegen/src/main/resources/Java/libraries/feign/ApiClient.mustache b/modules/swagger-codegen/src/main/resources/Java/libraries/feign/ApiClient.mustache index 7ce51e909ebc..3f2bfcebd5b5 100644 --- a/modules/swagger-codegen/src/main/resources/Java/libraries/feign/ApiClient.mustache +++ b/modules/swagger-codegen/src/main/resources/Java/libraries/feign/ApiClient.mustache @@ -46,7 +46,7 @@ public class ApiClient { */ public T buildClient(Class clientClass) { return Feign.builder() - .encoder(new JacksonEncoder(objectMapper)) + .encoder(new FormAwareEncoder(new JacksonEncoder(objectMapper))) .decoder(new JacksonDecoder(objectMapper)) // enable for basic auth: // .requestInterceptor(new feign.auth.BasicAuthRequestInterceptor(username, password)) diff --git a/modules/swagger-codegen/src/main/resources/Java/libraries/feign/FormAwareEncoder.mustache b/modules/swagger-codegen/src/main/resources/Java/libraries/feign/FormAwareEncoder.mustache new file mode 100644 index 000000000000..d0f026cced9a --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Java/libraries/feign/FormAwareEncoder.mustache @@ -0,0 +1,159 @@ +package {{invokerPackage}}; + +import java.io.*; +import java.lang.reflect.Type; +import java.net.URLEncoder; +import java.net.URLConnection; +import java.util.*; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; + +import feign.codec.Encoder; +import feign.RequestTemplate; + +{{>generatedAnnotation}} +public class FormAwareEncoder implements Encoder { + private static final String LINE_FEED = "\r\n"; + private static final String BOUNDARY = "----------------314159265358979323846"; + + private final Encoder delegate; + private DateFormat dateFormat; + + public FormAwareEncoder(Encoder delegate) { + this.delegate = delegate; + // Use RFC3339 format for date and datetime. + // See http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14 + this.dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); + + // Use UTC as the default time zone. + this.dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + } + + public void encode(Object object, Type bodyType, RequestTemplate template) { + if (object instanceof Map) { + StringBuilder formParamBuilder = new StringBuilder(); + Map formParams = (Map) object; + boolean isMultiPart = isMultiPart(formParams); + for (Map.Entry param : formParams.entrySet()) { + String keyStr = param.getKey(); + if (param.getValue() instanceof File) { + addFilePart(formParamBuilder, keyStr, (File) param.getValue()); + } else { + String valueStr = parameterToString(param.getValue()); + if (isMultiPart) { + addMultiPartFormField(formParamBuilder, keyStr, valueStr); + } else { + addEncodedFormField(formParamBuilder, keyStr, valueStr); + } + } + } + + if (isMultiPart) { + formParamBuilder.append(LINE_FEED); + formParamBuilder.append("--").append(BOUNDARY).append("--").append(LINE_FEED); + } + + String contentType = isMultiPart ? "multipart/form-data; boundary=" + BOUNDARY : "application/x-www-form-urlencoded"; + template.header("Content-type"); + template.header("Content-type", contentType); + template.header("MIME-Version", "1.0"); + template.body(formParamBuilder.toString()); + } else { + delegate.encode(object, bodyType, template); + } + } + + /* + * Currently only supports text files + */ + private void addFilePart(StringBuilder formParamBuilder, String fieldName, File uploadFile) { + try { + String fileName = uploadFile.getName(); + formParamBuilder.append("--").append(BOUNDARY).append(LINE_FEED); + formParamBuilder.append( + "Content-Disposition: form-data; name=\"" + fieldName + + "\"; filename=\"" + fileName + "\"") + .append(LINE_FEED); + formParamBuilder.append( + "Content-Type: " + + URLConnection.guessContentTypeFromName(fileName)) + .append(LINE_FEED); + formParamBuilder.append(LINE_FEED); + + BufferedReader reader = new BufferedReader(new FileReader(uploadFile)); + String line = ""; + while ((line = reader.readLine()) != null) { + formParamBuilder.append(line).append(LINE_FEED); + } + + formParamBuilder.append(LINE_FEED); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void addEncodedFormField(StringBuilder formParamBuilder, String name, String value) { + if (formParamBuilder.length() > 0) { + formParamBuilder.append("&"); + } + + try { + formParamBuilder.append(URLEncoder.encode(name, "utf8")) + .append("=") + .append(URLEncoder.encode(value, "utf8")); + } catch (UnsupportedEncodingException e) { + // move on to next + } + } + + private void addMultiPartFormField(StringBuilder formParamBuilder, String name, String value) { + formParamBuilder.append("--").append(BOUNDARY).append(LINE_FEED); + formParamBuilder.append("Content-Disposition: form-data; name=\"" + name + "\"") + .append(LINE_FEED); + formParamBuilder.append("Content-Type: text/plain; charset=utf-8").append( + LINE_FEED); + formParamBuilder.append(LINE_FEED); + formParamBuilder.append(value).append(LINE_FEED); + } + + private boolean isMultiPart(Map formParams) { + boolean isMultiPart = false; + for (Map.Entry entry : formParams.entrySet()) { + if (entry.getValue() instanceof File) { + isMultiPart = true; + break; + } + } + return isMultiPart; + } + + /** + * Format the given parameter object into string. + */ + public String parameterToString(Object param) { + if (param == null) { + return ""; + } else if (param instanceof Date) { + return formatDate((Date) param); + } else if (param instanceof Collection) { + StringBuilder b = new StringBuilder(); + for(Object o : (Collection)param) { + if(b.length() > 0) { + b.append(","); + } + b.append(String.valueOf(o)); + } + return b.toString(); + } else { + return String.valueOf(param); + } + } + + /** + * Format the given Date object into string. + */ + public String formatDate(Date date) { + return dateFormat.format(date); + } +} diff --git a/modules/swagger-codegen/src/main/resources/Java/libraries/feign/api.mustache b/modules/swagger-codegen/src/main/resources/Java/libraries/feign/api.mustache index 772079eebdbe..201068061022 100644 --- a/modules/swagger-codegen/src/main/resources/Java/libraries/feign/api.mustache +++ b/modules/swagger-codegen/src/main/resources/Java/libraries/feign/api.mustache @@ -25,10 +25,12 @@ public interface {{classname}} extends {{invokerPackage}}.ApiClient.Api { */ @RequestLine("{{httpMethod}} {{{path}}}{{#hasQueryParams}}?{{/hasQueryParams}}{{#queryParams}}{{paramName}}={{=<% %>=}}{<%paramName%>}<%={{ }}=%>{{#hasMore}}&{{/hasMore}}{{/queryParams}}") @Headers({ - {{#headerParams}}"{{paramName}}: {{=<% %>=}}{<%paramName%>}<%={{ }}=%>"{{#hasMore}}, + "Content-type: {{vendorExtensions.x-contentType}}", + "Accepts: {{vendorExtensions.x-accepts}}",{{#headerParams}} + "{{paramName}}: {{=<% %>=}}{<%paramName%>}<%={{ }}=%>"{{#hasMore}}, {{/hasMore}}{{/headerParams}} }) - {{#returnType}}{{{returnType}}} {{/returnType}}{{^returnType}}void {{/returnType}}{{nickname}} ({{#allParams}}@Param("{{paramName}}") {{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) throws ApiException; + {{#returnType}}{{{returnType}}} {{/returnType}}{{^returnType}}void {{/returnType}}{{nickname}}({{#allParams}}{{^vendorExtensions.x-isBody}}@Param("{{paramName}}") {{/vendorExtensions.x-isBody}}{{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) throws ApiException; {{/operation}} {{/operations}} } diff --git a/samples/client/petstore/java/feign/README.md b/samples/client/petstore/java/feign/README.md new file mode 100644 index 000000000000..8afc37518fc7 --- /dev/null +++ b/samples/client/petstore/java/feign/README.md @@ -0,0 +1,43 @@ +# swagger-java-client + +## Requirements + +Building the API client library requires [Maven](https://maven.apache.org/) to be installed. + +## Installation & Usage + +To install the API client library to your local Maven repository, simply execute: + +```shell +mvn install +``` + +To deploy it to a remote Maven repository instead, configure the settings of the repository and execute: + +```shell +mvn deploy +``` + +Refer to the [official documentation](https://maven.apache.org/plugins/maven-deploy-plugin/usage.html) for more information. + +After the client libarary is installed/deployed, you can use it in your Maven project by adding the following to your *pom.xml*: + +```xml + + io.swagger + swagger-java-client + 1.0.0 + compile + + +``` + +## Recommendation + +It's recommended to create an instance of `ApiClient` per thread in a multithreaded environment to avoid any potential issue. + +## Author + +apiteam@swagger.io + + diff --git a/samples/client/petstore/java/feign/build.gradle b/samples/client/petstore/java/feign/build.gradle new file mode 100644 index 000000000000..383e0a1dc956 --- /dev/null +++ b/samples/client/petstore/java/feign/build.gradle @@ -0,0 +1,113 @@ +group = 'io.swagger' +version = '1.0.0' + +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.2.2' + classpath 'com.github.dcendents:android-maven-plugin:1.2' + } +} + +repositories { + jcenter() +} + + +if(hasProperty('target') && target == 'android') { + + apply plugin: 'com.android.library' + apply plugin: 'com.github.dcendents.android-maven' + + android { + compileSdkVersion 22 + buildToolsVersion '22.0.0' + defaultConfig { + minSdkVersion 14 + targetSdkVersion 22 + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_7 + targetCompatibility JavaVersion.VERSION_1_7 + } + + // Rename the aar correctly + libraryVariants.all { variant -> + variant.outputs.each { output -> + def outputFile = output.outputFile + if (outputFile != null && outputFile.name.endsWith('.aar')) { + def fileName = "${project.name}-${variant.baseName}-${version}.aar" + output.outputFile = new File(outputFile.parent, fileName) + } + } + } + + dependencies { + provided 'javax.annotation:jsr250-api:1.0' + } + } + + afterEvaluate { + android.libraryVariants.all { variant -> + def task = project.tasks.create "jar${variant.name.capitalize()}", Jar + task.description = "Create jar artifact for ${variant.name}" + task.dependsOn variant.javaCompile + task.from variant.javaCompile.destinationDir + task.destinationDir = project.file("${project.buildDir}/outputs/jar") + task.archiveName = "${project.name}-${variant.baseName}-${version}.jar" + artifacts.add('archives', task); + } + } + + task sourcesJar(type: Jar) { + from android.sourceSets.main.java.srcDirs + classifier = 'sources' + } + + artifacts { + archives sourcesJar + } + +} else { + + apply plugin: 'java' + apply plugin: 'maven' + + sourceCompatibility = JavaVersion.VERSION_1_7 + targetCompatibility = JavaVersion.VERSION_1_7 + + install { + repositories.mavenInstaller { + pom.artifactId = 'swagger-java-client' + } + } + + task execute(type:JavaExec) { + main = System.getProperty('mainClass') + classpath = sourceSets.main.runtimeClasspath + } +} + +ext { + swagger_annotations_version = "1.5.0" + jackson_version = "2.6.3" + feign_version = "8.1.1" + jodatime_version = "2.5" + junit_version = "4.12" +} + +dependencies { + compile "io.swagger:swagger-annotations:$swagger_annotations_version" + compile "com.netflix.feign:feign-core:$feign_version" + compile "com.netflix.feign:feign-jackson:$feign_version" + compile "com.netflix.feign:feign-slf4j:$feign_version" + compile "com.fasterxml.jackson.core:jackson-core:$jackson_version" + compile "com.fasterxml.jackson.core:jackson-annotations:$jackson_version" + compile "com.fasterxml.jackson.core:jackson-databind:$jackson_version" + compile "com.fasterxml.jackson.datatype:jackson-datatype-joda:2.1.5" + compile "joda-time:joda-time:$jodatime_version" + compile "com.brsanthu:migbase64:2.2" + testCompile "junit:junit:$junit_version" +} diff --git a/samples/client/petstore/java/feign/gradle.properties b/samples/client/petstore/java/feign/gradle.properties new file mode 100644 index 000000000000..05644f0754af --- /dev/null +++ b/samples/client/petstore/java/feign/gradle.properties @@ -0,0 +1,2 @@ +# Uncomment to build for Android +#target = android \ No newline at end of file diff --git a/samples/client/petstore/java/feign/pom.xml b/samples/client/petstore/java/feign/pom.xml new file mode 100644 index 000000000000..967bdabcc6bc --- /dev/null +++ b/samples/client/petstore/java/feign/pom.xml @@ -0,0 +1,183 @@ + + 4.0.0 + io.swagger + swagger-java-client + jar + swagger-java-client + 1.0.0 + + scm:git:git@github.com:swagger-api/swagger-mustache.git + scm:git:git@github.com:swagger-api/swagger-codegen.git + https://github.com/swagger-api/swagger-codegen + + + 2.2.0 + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.12 + + + + loggerPath + conf/log4j.properties + + + -Xms512m -Xmx1500m + methods + pertest + + + + maven-dependency-plugin + + + package + + copy-dependencies + + + ${project.build.directory}/lib + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.2 + + + + jar + test-jar + + + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + add_sources + generate-sources + + add-source + + + + src/main/java + + + + + add_test_sources + generate-test-sources + + add-test-source + + + + src/test/java + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.6 + 1.6 + + + + + + + io.swagger + swagger-annotations + ${swagger-annotations-version} + + + + + com.netflix.feign + feign-core + ${feign-version} + + + com.netflix.feign + feign-jackson + ${feign-version} + + + com.netflix.feign + feign-slf4j + ${feign-version} + + + + + com.fasterxml.jackson.core + jackson-core + ${jackson-version} + + + com.fasterxml.jackson.core + jackson-annotations + ${jackson-version} + + + com.fasterxml.jackson.core + jackson-databind + ${jackson-version} + + + com.fasterxml.jackson.datatype + jackson-datatype-joda + 2.1.5 + + + joda-time + joda-time + ${jodatime-version} + + + + + com.brsanthu + migbase64 + 2.2 + + + + + junit + junit + ${junit-version} + test + + + + 1.5.0 + 8.1.1 + 2.6.3 + 2.5 + 4.12 + 1.0.0 + + diff --git a/samples/client/petstore/java/feign/settings.gradle b/samples/client/petstore/java/feign/settings.gradle new file mode 100644 index 000000000000..55640f75122e --- /dev/null +++ b/samples/client/petstore/java/feign/settings.gradle @@ -0,0 +1 @@ +rootProject.name = "swagger-java-client" \ No newline at end of file diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/ApiClient.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/ApiClient.java new file mode 100644 index 000000000000..e486c713a923 --- /dev/null +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/ApiClient.java @@ -0,0 +1,86 @@ +package io.swagger.client; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import feign.Feign; +import feign.jackson.JacksonDecoder; +import feign.jackson.JacksonEncoder; +import feign.slf4j.Slf4jLogger; + +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T01:11:21.159-05:00") +public class ApiClient { + public interface Api {} + + private ObjectMapper objectMapper; + private String basePath = "http://petstore.swagger.io/v2"; + + public ApiClient() { + objectMapper = createObjectMapper(); + } + + public String getBasePath() { + return basePath; + } + + public ApiClient setBasePath(String basePath) { + this.basePath = basePath; + return this; + } + + private ObjectMapper createObjectMapper() { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING); + objectMapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING); + return objectMapper; + } + + /** + * Creates a feign client for given API interface. + * + * Usage: + * ApiClient apiClient = new ApiClient(); + * apiClient.setBasePath("http://localhost:8080"); + * XYZApi api = apiClient.buildClient(XYZApi.class); + * XYZResponse response = api.someMethod(...); + */ + public T buildClient(Class clientClass) { + return Feign.builder() + .encoder(new FormAwareEncoder(new JacksonEncoder(objectMapper))) + .decoder(new JacksonDecoder(objectMapper)) +// enable for basic auth: +// .requestInterceptor(new feign.auth.BasicAuthRequestInterceptor(username, password)) + .logger(new Slf4jLogger()) + .target(clientClass, basePath); + } + + /** + * Select the Accept header's value from the given accepts array: + * if JSON exists in the given array, use it; + * otherwise use all of them (joining into a string) + * + * @param accepts The accepts array to select from + * @return The Accept header to use. If the given array is empty, + * null will be returned (not to set the Accept header explicitly). + */ + public String selectHeaderAccept(String[] accepts) { + if (accepts.length == 0) return null; + if (StringUtil.containsIgnoreCase(accepts, "application/json")) return "application/json"; + return StringUtil.join(accepts, ","); + } + + /** + * Select the Content-Type header's value from the given array: + * if JSON exists in the given array, use it; + * otherwise use the first one of the array. + * + * @param contentTypes The Content-Type array to select from + * @return The Content-Type header to use. If the given array is empty, + * JSON will be used. + */ + public String selectHeaderContentType(String[] contentTypes) { + if (contentTypes.length == 0) return "application/json"; + if (StringUtil.containsIgnoreCase(contentTypes, "application/json")) return "application/json"; + return contentTypes[0]; + } +} diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/FormAwareEncoder.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/FormAwareEncoder.java new file mode 100644 index 000000000000..3ec3c6b92747 --- /dev/null +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/FormAwareEncoder.java @@ -0,0 +1,159 @@ +package io.swagger.client; + +import java.io.*; +import java.lang.reflect.Type; +import java.net.URLEncoder; +import java.net.URLConnection; +import java.util.*; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; + +import feign.codec.Encoder; +import feign.RequestTemplate; + +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T01:11:21.159-05:00") +public class FormAwareEncoder implements Encoder { + private static final String LINE_FEED = "\r\n"; + private static final String BOUNDARY = "----------------314159265358979323846"; + + private final Encoder delegate; + private DateFormat dateFormat; + + public FormAwareEncoder(Encoder delegate) { + this.delegate = delegate; + // Use RFC3339 format for date and datetime. + // See http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14 + this.dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); + + // Use UTC as the default time zone. + this.dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + } + + public void encode(Object object, Type bodyType, RequestTemplate template) { + if (object instanceof Map) { + StringBuilder formParamBuilder = new StringBuilder(); + Map formParams = (Map) object; + boolean isMultiPart = isMultiPart(formParams); + for (Map.Entry param : formParams.entrySet()) { + String keyStr = param.getKey(); + if (param.getValue() instanceof File) { + addFilePart(formParamBuilder, keyStr, (File) param.getValue()); + } else { + String valueStr = parameterToString(param.getValue()); + if (isMultiPart) { + addMultiPartFormField(formParamBuilder, keyStr, valueStr); + } else { + addEncodedFormField(formParamBuilder, keyStr, valueStr); + } + } + } + + if (isMultiPart) { + formParamBuilder.append(LINE_FEED); + formParamBuilder.append("--").append(BOUNDARY).append("--").append(LINE_FEED); + } + + String contentType = isMultiPart ? "multipart/form-data; boundary=" + BOUNDARY : "application/x-www-form-urlencoded"; + template.header("Content-type"); + template.header("Content-type", contentType); + template.header("MIME-Version", "1.0"); + template.body(formParamBuilder.toString()); + } else { + delegate.encode(object, bodyType, template); + } + } + + /* + * Currently only supports text files + */ + private void addFilePart(StringBuilder formParamBuilder, String fieldName, File uploadFile) { + try { + String fileName = uploadFile.getName(); + formParamBuilder.append("--").append(BOUNDARY).append(LINE_FEED); + formParamBuilder.append( + "Content-Disposition: form-data; name=\"" + fieldName + + "\"; filename=\"" + fileName + "\"") + .append(LINE_FEED); + formParamBuilder.append( + "Content-Type: " + + URLConnection.guessContentTypeFromName(fileName)) + .append(LINE_FEED); + formParamBuilder.append(LINE_FEED); + + BufferedReader reader = new BufferedReader(new FileReader(uploadFile)); + String line = ""; + while ((line = reader.readLine()) != null) { + formParamBuilder.append(line).append(LINE_FEED); + } + + formParamBuilder.append(LINE_FEED); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void addEncodedFormField(StringBuilder formParamBuilder, String name, String value) { + if (formParamBuilder.length() > 0) { + formParamBuilder.append("&"); + } + + try { + formParamBuilder.append(URLEncoder.encode(name, "utf8")) + .append("=") + .append(URLEncoder.encode(value, "utf8")); + } catch (UnsupportedEncodingException e) { + // move on to next + } + } + + private void addMultiPartFormField(StringBuilder formParamBuilder, String name, String value) { + formParamBuilder.append("--").append(BOUNDARY).append(LINE_FEED); + formParamBuilder.append("Content-Disposition: form-data; name=\"" + name + "\"") + .append(LINE_FEED); + formParamBuilder.append("Content-Type: text/plain; charset=utf-8").append( + LINE_FEED); + formParamBuilder.append(LINE_FEED); + formParamBuilder.append(value).append(LINE_FEED); + } + + private boolean isMultiPart(Map formParams) { + boolean isMultiPart = false; + for (Map.Entry entry : formParams.entrySet()) { + if (entry.getValue() instanceof File) { + isMultiPart = true; + break; + } + } + return isMultiPart; + } + + /** + * Format the given parameter object into string. + */ + public String parameterToString(Object param) { + if (param == null) { + return ""; + } else if (param instanceof Date) { + return formatDate((Date) param); + } else if (param instanceof Collection) { + StringBuilder b = new StringBuilder(); + for(Object o : (Collection)param) { + if(b.length() > 0) { + b.append(","); + } + b.append(String.valueOf(o)); + } + return b.toString(); + } else { + return String.valueOf(param); + } + } + + /** + * Format the given Date object into string. + */ + public String formatDate(Date date) { + return dateFormat.format(date); + } +} diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/StringUtil.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/StringUtil.java new file mode 100644 index 000000000000..b0704ea88ca9 --- /dev/null +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/StringUtil.java @@ -0,0 +1,51 @@ +package io.swagger.client; + +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T01:11:21.159-05:00") +public class StringUtil { + /** + * Check if the given array contains the given value (with case-insensitive comparison). + * + * @param array The array + * @param value The value to search + * @return true if the array contains the value + */ + public static boolean containsIgnoreCase(String[] array, String value) { + for (String str : array) { + if (value == null && str == null) return true; + if (value != null && value.equalsIgnoreCase(str)) return true; + } + return false; + } + + /** + * Join an array of strings with the given separator. + *

+ * Note: This might be replaced by utility method from commons-lang or guava someday + * if one of those libraries is added as dependency. + *

+ * + * @param array The array of strings + * @param separator The separator + * @return the resulting string + */ + public static String join(String[] array, String separator) { + int len = array.length; + if (len == 0) return ""; + + StringBuilder out = new StringBuilder(); + out.append(array[0]); + for (int i = 1; i < len; i++) { + out.append(separator).append(array[i]); + } + return out.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + public static String toIndentedString(Object o) { + if (o == null) return "null"; + return o.toString().replace("\n", "\n "); + } +} diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/PetApi.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/PetApi.java new file mode 100644 index 000000000000..e4fe4e4e2bf9 --- /dev/null +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/PetApi.java @@ -0,0 +1,133 @@ +package io.swagger.client.api; + +import io.swagger.client.ApiException; +import io.swagger.client.ApiClient; +import io.swagger.client.Configuration; +import io.swagger.client.Pair; +import io.swagger.client.TypeRef; + +import io.swagger.client.model.Pet; +import java.io.File; +import io.swagger.client.model.ApiResponse; + + +import java.util.*; + +import feign.*; + +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T01:11:21.159-05:00") +public interface PetApi extends io.swagger.client.ApiClient.Api { + + + /** + * Update an existing pet + * + * @param body Pet object that needs to be added to the store + * @return void + */ + @RequestLine("PUT /pet") + @Headers({ + "Content-type: application/json", + "Accepts: application/json", + }) + void updatePet(Pet body) throws ApiException; + + /** + * Add a new pet to the store + * + * @param body Pet object that needs to be added to the store + * @return void + */ + @RequestLine("POST /pet") + @Headers({ + "Content-type: application/json", + "Accepts: application/json", + }) + void addPet(Pet body) throws ApiException; + + /** + * Finds Pets by status + * Multiple status values can be provided with comma seperated strings + * @param status Status values that need to be considered for filter + * @return List + */ + @RequestLine("GET /pet/findByStatus?status={status}") + @Headers({ + "Content-type: application/json", + "Accepts: application/json", + }) + List findPetsByStatus(@Param("status") List status) throws ApiException; + + /** + * Finds Pets by tags + * Muliple tags can be provided with comma seperated strings. Use tag1, tag2, tag3 for testing. + * @param tags Tags to filter by + * @return List + */ + @RequestLine("GET /pet/findByTags?tags={tags}") + @Headers({ + "Content-type: application/json", + "Accepts: application/json", + }) + List findPetsByTags(@Param("tags") List tags) throws ApiException; + + /** + * Find pet by ID + * Returns a single pet + * @param petId ID of pet to return + * @return Pet + */ + @RequestLine("GET /pet/{petId}") + @Headers({ + "Content-type: application/json", + "Accepts: application/json", + }) + Pet getPetById(@Param("petId") Long petId) throws ApiException; + + /** + * Updates a pet in the store with form data + * + * @param petId ID of pet that needs to be updated + * @param name Updated name of the pet + * @param status Updated status of the pet + * @return void + */ + @RequestLine("POST /pet/{petId}") + @Headers({ + "Content-type: application/x-www-form-urlencoded", + "Accepts: application/json", + }) + void updatePetWithForm(@Param("petId") Long petId, @Param("name") String name, @Param("status") String status) throws ApiException; + + /** + * Deletes a pet + * + * @param petId Pet id to delete + * @param apiKey + * @return void + */ + @RequestLine("DELETE /pet/{petId}") + @Headers({ + "Content-type: application/json", + "Accepts: application/json", + "apiKey: {apiKey}" + }) + void deletePet(@Param("petId") Long petId, @Param("apiKey") String apiKey) throws ApiException; + + /** + * uploads an image + * + * @param petId ID of pet to update + * @param additionalMetadata Additional data to pass to server + * @param file file to upload + * @return ApiResponse + */ + @RequestLine("POST /pet/{petId}/uploadImage") + @Headers({ + "Content-type: multipart/form-data", + "Accepts: application/json", + }) + ApiResponse uploadFile(@Param("petId") Long petId, @Param("additionalMetadata") String additionalMetadata, @Param("file") File file) throws ApiException; + + +} diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/StoreApi.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/StoreApi.java new file mode 100644 index 000000000000..87321de5df75 --- /dev/null +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/StoreApi.java @@ -0,0 +1,73 @@ +package io.swagger.client.api; + +import io.swagger.client.ApiException; +import io.swagger.client.ApiClient; +import io.swagger.client.Configuration; +import io.swagger.client.Pair; +import io.swagger.client.TypeRef; + +import java.util.Map; +import io.swagger.client.model.Order; + + +import java.util.*; + +import feign.*; + +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T01:11:21.159-05:00") +public interface StoreApi extends io.swagger.client.ApiClient.Api { + + + /** + * Returns pet inventories by status + * Returns a map of status codes to quantities + * @return Map + */ + @RequestLine("GET /store/inventory") + @Headers({ + "Content-type: application/json", + "Accepts: application/json", + }) + Map getInventory() throws ApiException; + + /** + * Place an order for a pet + * + * @param body order placed for purchasing the pet + * @return Order + */ + @RequestLine("POST /store/order") + @Headers({ + "Content-type: application/json", + "Accepts: application/json", + }) + Order placeOrder(Order body) throws ApiException; + + /** + * Find purchase order by ID + * For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions + * @param orderId ID of pet that needs to be fetched + * @return Order + */ + @RequestLine("GET /store/order/{orderId}") + @Headers({ + "Content-type: application/json", + "Accepts: application/json", + }) + Order getOrderById(@Param("orderId") Long orderId) throws ApiException; + + /** + * Delete purchase order by ID + * For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors + * @param orderId ID of the order that needs to be deleted + * @return void + */ + @RequestLine("DELETE /store/order/{orderId}") + @Headers({ + "Content-type: application/json", + "Accepts: application/json", + }) + void deleteOrder(@Param("orderId") String orderId) throws ApiException; + + +} diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/UserApi.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/UserApi.java new file mode 100644 index 000000000000..070ca861818c --- /dev/null +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/UserApi.java @@ -0,0 +1,127 @@ +package io.swagger.client.api; + +import io.swagger.client.ApiException; +import io.swagger.client.ApiClient; +import io.swagger.client.Configuration; +import io.swagger.client.Pair; +import io.swagger.client.TypeRef; + +import io.swagger.client.model.User; +import java.util.*; + + +import java.util.*; + +import feign.*; + +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T01:11:21.159-05:00") +public interface UserApi extends io.swagger.client.ApiClient.Api { + + + /** + * Create user + * This can only be done by the logged in user. + * @param body Created user object + * @return void + */ + @RequestLine("POST /user") + @Headers({ + "Content-type: application/json", + "Accepts: application/json", + }) + void createUser(User body) throws ApiException; + + /** + * Creates list of users with given input array + * + * @param body List of user object + * @return void + */ + @RequestLine("POST /user/createWithArray") + @Headers({ + "Content-type: application/json", + "Accepts: application/json", + }) + void createUsersWithArrayInput(List body) throws ApiException; + + /** + * Creates list of users with given input array + * + * @param body List of user object + * @return void + */ + @RequestLine("POST /user/createWithList") + @Headers({ + "Content-type: application/json", + "Accepts: application/json", + }) + void createUsersWithListInput(List body) throws ApiException; + + /** + * Logs user into the system + * + * @param username The user name for login + * @param password The password for login in clear text + * @return String + */ + @RequestLine("GET /user/login?username={username}&password={password}") + @Headers({ + "Content-type: application/json", + "Accepts: application/json", + }) + String loginUser(@Param("username") String username, @Param("password") String password) throws ApiException; + + /** + * Logs out current logged in user session + * + * @return void + */ + @RequestLine("GET /user/logout") + @Headers({ + "Content-type: application/json", + "Accepts: application/json", + }) + void logoutUser() throws ApiException; + + /** + * Get user by user name + * + * @param username The name that needs to be fetched. Use user1 for testing. + * @return User + */ + @RequestLine("GET /user/{username}") + @Headers({ + "Content-type: application/json", + "Accepts: application/json", + }) + User getUserByName(@Param("username") String username) throws ApiException; + + /** + * Updated user + * This can only be done by the logged in user. + * @param username name that need to be deleted + * @param body Updated user object + * @return void + */ + @RequestLine("PUT /user/{username}") + @Headers({ + "Content-type: application/json", + "Accepts: application/json", + }) + void updateUser(@Param("username") String username, User body) throws ApiException; + + /** + * Delete user + * This can only be done by the logged in user. + * @param username The name that needs to be deleted + * @return void + */ + @RequestLine("DELETE /user/{username}") + @Headers({ + "Content-type: application/json", + "Accepts: application/json", + }) + void deleteUser(@Param("username") String username) throws ApiException; + + +} diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/ApiResponse.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/ApiResponse.java new file mode 100644 index 000000000000..f06d10acff27 --- /dev/null +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/ApiResponse.java @@ -0,0 +1,92 @@ +package io.swagger.client.model; + +import io.swagger.client.StringUtil; + + + +import java.util.Objects; + +import io.swagger.annotations.*; +import com.fasterxml.jackson.annotation.JsonProperty; + + + +@ApiModel(description = "") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T01:11:21.159-05:00") +public class ApiResponse { + + private Integer code = null; + private String type = null; + private String message = null; + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("code") + public Integer getCode() { + return code; + } + public void setCode(Integer code) { + this.code = code; + } + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("type") + public String getType() { + return type; + } + public void setType(String type) { + this.type = type; + } + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("message") + public String getMessage() { + return message; + } + public void setMessage(String message) { + this.message = message; + } + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ApiResponse apiResponse = (ApiResponse) o; + return Objects.equals(code, apiResponse.code) && + Objects.equals(type, apiResponse.type) && + Objects.equals(message, apiResponse.message); + } + + @Override + public int hashCode() { + return Objects.hash(code, type, message); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ApiResponse {\n"); + + sb.append(" code: ").append(StringUtil.toIndentedString(code)).append("\n"); + sb.append(" type: ").append(StringUtil.toIndentedString(type)).append("\n"); + sb.append(" message: ").append(StringUtil.toIndentedString(message)).append("\n"); + sb.append("}"); + return sb.toString(); + } +} + + diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Category.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Category.java new file mode 100644 index 000000000000..8edf7db00513 --- /dev/null +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Category.java @@ -0,0 +1,77 @@ +package io.swagger.client.model; + +import io.swagger.client.StringUtil; + + + +import java.util.Objects; + +import io.swagger.annotations.*; +import com.fasterxml.jackson.annotation.JsonProperty; + + + +@ApiModel(description = "") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T01:11:21.159-05:00") +public class Category { + + private Long id = null; + private String name = null; + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("id") + public Long getId() { + return id; + } + public void setId(Long id) { + this.id = id; + } + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("name") + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Category category = (Category) o; + return Objects.equals(id, category.id) && + Objects.equals(name, category.name); + } + + @Override + public int hashCode() { + return Objects.hash(id, name); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Category {\n"); + + sb.append(" id: ").append(StringUtil.toIndentedString(id)).append("\n"); + sb.append(" name: ").append(StringUtil.toIndentedString(name)).append("\n"); + sb.append("}"); + return sb.toString(); + } +} + + diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Order.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Order.java new file mode 100644 index 000000000000..a057e4899f02 --- /dev/null +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Order.java @@ -0,0 +1,157 @@ +package io.swagger.client.model; + +import io.swagger.client.StringUtil; +import java.util.Date; + + + +import java.util.Objects; + +import io.swagger.annotations.*; +import com.fasterxml.jackson.annotation.JsonProperty; + + + +@ApiModel(description = "") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T01:11:21.159-05:00") +public class Order { + + private Long id = null; + private Long petId = null; + private Integer quantity = null; + private Date shipDate = null; + +public enum StatusEnum { + PLACED("placed"), + APPROVED("approved"), + DELIVERED("delivered"); + + private String value; + + StatusEnum(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } +} + + private StatusEnum status = null; + private Boolean complete = false; + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("id") + public Long getId() { + return id; + } + public void setId(Long id) { + this.id = id; + } + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("petId") + public Long getPetId() { + return petId; + } + public void setPetId(Long petId) { + this.petId = petId; + } + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("quantity") + public Integer getQuantity() { + return quantity; + } + public void setQuantity(Integer quantity) { + this.quantity = quantity; + } + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("shipDate") + public Date getShipDate() { + return shipDate; + } + public void setShipDate(Date shipDate) { + this.shipDate = shipDate; + } + + + /** + * Order Status + **/ + @ApiModelProperty(value = "Order Status") + @JsonProperty("status") + public StatusEnum getStatus() { + return status; + } + public void setStatus(StatusEnum status) { + this.status = status; + } + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("complete") + public Boolean getComplete() { + return complete; + } + public void setComplete(Boolean complete) { + this.complete = complete; + } + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Order order = (Order) o; + return Objects.equals(id, order.id) && + Objects.equals(petId, order.petId) && + Objects.equals(quantity, order.quantity) && + Objects.equals(shipDate, order.shipDate) && + Objects.equals(status, order.status) && + Objects.equals(complete, order.complete); + } + + @Override + public int hashCode() { + return Objects.hash(id, petId, quantity, shipDate, status, complete); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Order {\n"); + + sb.append(" id: ").append(StringUtil.toIndentedString(id)).append("\n"); + sb.append(" petId: ").append(StringUtil.toIndentedString(petId)).append("\n"); + sb.append(" quantity: ").append(StringUtil.toIndentedString(quantity)).append("\n"); + sb.append(" shipDate: ").append(StringUtil.toIndentedString(shipDate)).append("\n"); + sb.append(" status: ").append(StringUtil.toIndentedString(status)).append("\n"); + sb.append(" complete: ").append(StringUtil.toIndentedString(complete)).append("\n"); + sb.append("}"); + return sb.toString(); + } +} + + diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Pet.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Pet.java new file mode 100644 index 000000000000..a844cfa8a836 --- /dev/null +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Pet.java @@ -0,0 +1,159 @@ +package io.swagger.client.model; + +import io.swagger.client.StringUtil; +import io.swagger.client.model.Category; +import java.util.*; +import io.swagger.client.model.Tag; + + + +import java.util.Objects; + +import io.swagger.annotations.*; +import com.fasterxml.jackson.annotation.JsonProperty; + + + +@ApiModel(description = "") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T01:11:21.159-05:00") +public class Pet { + + private Long id = null; + private Category category = null; + private String name = null; + private List photoUrls = new ArrayList(); + private List tags = new ArrayList(); + +public enum StatusEnum { + AVAILABLE("available"), + PENDING("pending"), + SOLD("sold"); + + private String value; + + StatusEnum(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } +} + + private StatusEnum status = null; + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("id") + public Long getId() { + return id; + } + public void setId(Long id) { + this.id = id; + } + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("category") + public Category getCategory() { + return category; + } + public void setCategory(Category category) { + this.category = category; + } + + + /** + **/ + @ApiModelProperty(required = true, value = "") + @JsonProperty("name") + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + + + /** + **/ + @ApiModelProperty(required = true, value = "") + @JsonProperty("photoUrls") + public List getPhotoUrls() { + return photoUrls; + } + public void setPhotoUrls(List photoUrls) { + this.photoUrls = photoUrls; + } + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("tags") + public List getTags() { + return tags; + } + public void setTags(List tags) { + this.tags = tags; + } + + + /** + * pet status in the store + **/ + @ApiModelProperty(value = "pet status in the store") + @JsonProperty("status") + public StatusEnum getStatus() { + return status; + } + public void setStatus(StatusEnum status) { + this.status = status; + } + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Pet pet = (Pet) o; + return Objects.equals(id, pet.id) && + Objects.equals(category, pet.category) && + Objects.equals(name, pet.name) && + Objects.equals(photoUrls, pet.photoUrls) && + Objects.equals(tags, pet.tags) && + Objects.equals(status, pet.status); + } + + @Override + public int hashCode() { + return Objects.hash(id, category, name, photoUrls, tags, status); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Pet {\n"); + + sb.append(" id: ").append(StringUtil.toIndentedString(id)).append("\n"); + sb.append(" category: ").append(StringUtil.toIndentedString(category)).append("\n"); + sb.append(" name: ").append(StringUtil.toIndentedString(name)).append("\n"); + sb.append(" photoUrls: ").append(StringUtil.toIndentedString(photoUrls)).append("\n"); + sb.append(" tags: ").append(StringUtil.toIndentedString(tags)).append("\n"); + sb.append(" status: ").append(StringUtil.toIndentedString(status)).append("\n"); + sb.append("}"); + return sb.toString(); + } +} + + diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Tag.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Tag.java new file mode 100644 index 000000000000..7995cbcaa9c6 --- /dev/null +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Tag.java @@ -0,0 +1,77 @@ +package io.swagger.client.model; + +import io.swagger.client.StringUtil; + + + +import java.util.Objects; + +import io.swagger.annotations.*; +import com.fasterxml.jackson.annotation.JsonProperty; + + + +@ApiModel(description = "") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T01:11:21.159-05:00") +public class Tag { + + private Long id = null; + private String name = null; + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("id") + public Long getId() { + return id; + } + public void setId(Long id) { + this.id = id; + } + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("name") + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Tag tag = (Tag) o; + return Objects.equals(id, tag.id) && + Objects.equals(name, tag.name); + } + + @Override + public int hashCode() { + return Objects.hash(id, name); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Tag {\n"); + + sb.append(" id: ").append(StringUtil.toIndentedString(id)).append("\n"); + sb.append(" name: ").append(StringUtil.toIndentedString(name)).append("\n"); + sb.append("}"); + return sb.toString(); + } +} + + diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/User.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/User.java new file mode 100644 index 000000000000..d0d004b8c118 --- /dev/null +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/User.java @@ -0,0 +1,168 @@ +package io.swagger.client.model; + +import io.swagger.client.StringUtil; + + + +import java.util.Objects; + +import io.swagger.annotations.*; +import com.fasterxml.jackson.annotation.JsonProperty; + + + +@ApiModel(description = "") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T01:11:21.159-05:00") +public class User { + + private Long id = null; + private String username = null; + private String firstName = null; + private String lastName = null; + private String email = null; + private String password = null; + private String phone = null; + private Integer userStatus = null; + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("id") + public Long getId() { + return id; + } + public void setId(Long id) { + this.id = id; + } + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("username") + public String getUsername() { + return username; + } + public void setUsername(String username) { + this.username = username; + } + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("firstName") + public String getFirstName() { + return firstName; + } + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("lastName") + public String getLastName() { + return lastName; + } + public void setLastName(String lastName) { + this.lastName = lastName; + } + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("email") + public String getEmail() { + return email; + } + public void setEmail(String email) { + this.email = email; + } + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("password") + public String getPassword() { + return password; + } + public void setPassword(String password) { + this.password = password; + } + + + /** + **/ + @ApiModelProperty(value = "") + @JsonProperty("phone") + public String getPhone() { + return phone; + } + public void setPhone(String phone) { + this.phone = phone; + } + + + /** + * User Status + **/ + @ApiModelProperty(value = "User Status") + @JsonProperty("userStatus") + public Integer getUserStatus() { + return userStatus; + } + public void setUserStatus(Integer userStatus) { + this.userStatus = userStatus; + } + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + User user = (User) o; + return Objects.equals(id, user.id) && + Objects.equals(username, user.username) && + Objects.equals(firstName, user.firstName) && + Objects.equals(lastName, user.lastName) && + Objects.equals(email, user.email) && + Objects.equals(password, user.password) && + Objects.equals(phone, user.phone) && + Objects.equals(userStatus, user.userStatus); + } + + @Override + public int hashCode() { + return Objects.hash(id, username, firstName, lastName, email, password, phone, userStatus); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class User {\n"); + + sb.append(" id: ").append(StringUtil.toIndentedString(id)).append("\n"); + sb.append(" username: ").append(StringUtil.toIndentedString(username)).append("\n"); + sb.append(" firstName: ").append(StringUtil.toIndentedString(firstName)).append("\n"); + sb.append(" lastName: ").append(StringUtil.toIndentedString(lastName)).append("\n"); + sb.append(" email: ").append(StringUtil.toIndentedString(email)).append("\n"); + sb.append(" password: ").append(StringUtil.toIndentedString(password)).append("\n"); + sb.append(" phone: ").append(StringUtil.toIndentedString(phone)).append("\n"); + sb.append(" userStatus: ").append(StringUtil.toIndentedString(userStatus)).append("\n"); + sb.append("}"); + return sb.toString(); + } +} + + diff --git a/samples/client/petstore/java/feign/src/test/java/io/swagger/client/StringUtilTest.java b/samples/client/petstore/java/feign/src/test/java/io/swagger/client/StringUtilTest.java new file mode 100644 index 000000000000..c93908b84821 --- /dev/null +++ b/samples/client/petstore/java/feign/src/test/java/io/swagger/client/StringUtilTest.java @@ -0,0 +1,32 @@ +package io.swagger.client; + +import org.junit.*; +import static org.junit.Assert.*; + +public class StringUtilTest { + @Test + public void testContainsIgnoreCase() { + assertTrue(StringUtil.containsIgnoreCase(new String[]{"abc"}, "abc")); + assertTrue(StringUtil.containsIgnoreCase(new String[]{"abc"}, "ABC")); + assertTrue(StringUtil.containsIgnoreCase(new String[]{"ABC"}, "abc")); + assertTrue(StringUtil.containsIgnoreCase(new String[]{null, "abc"}, "ABC")); + assertTrue(StringUtil.containsIgnoreCase(new String[]{null, "abc"}, null)); + + assertFalse(StringUtil.containsIgnoreCase(new String[]{"abc"}, "def")); + assertFalse(StringUtil.containsIgnoreCase(new String[]{}, "ABC")); + assertFalse(StringUtil.containsIgnoreCase(new String[]{}, null)); + } + + @Test + public void testJoin() { + String[] array = {"aa", "bb", "cc"}; + assertEquals("aa,bb,cc", StringUtil.join(array, ",")); + assertEquals("aa, bb, cc", StringUtil.join(array, ", ")); + assertEquals("aabbcc", StringUtil.join(array, "")); + assertEquals("aa bb cc", StringUtil.join(array, " ")); + assertEquals("aa\nbb\ncc", StringUtil.join(array, "\n")); + + assertEquals("", StringUtil.join(new String[]{}, ",")); + assertEquals("abc", StringUtil.join(new String[]{"abc"}, ",")); + } +} \ No newline at end of file diff --git a/samples/client/petstore/java/feign/src/test/java/io/swagger/petstore/test/PetApiTest.java b/samples/client/petstore/java/feign/src/test/java/io/swagger/petstore/test/PetApiTest.java new file mode 100644 index 000000000000..402d60b37c29 --- /dev/null +++ b/samples/client/petstore/java/feign/src/test/java/io/swagger/petstore/test/PetApiTest.java @@ -0,0 +1,199 @@ +package io.swagger.petstore.test; + +import io.swagger.client.ApiClient; + +import io.swagger.client.api.*; +import io.swagger.client.model.*; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.junit.*; +import static org.junit.Assert.*; + +public class PetApiTest { + ApiClient apiClient; + PetApi api; + + @Before + public void setup() { + apiClient = new ApiClient(); + api = apiClient.buildClient(PetApi.class); + } + + @Test + public void testApiClient() { + // the default api client is used + assertEquals("http://petstore.swagger.io/v2", apiClient.getBasePath()); + + ApiClient newClient = new ApiClient(); + newClient.setBasePath("http://example.com"); + + assertEquals("http://example.com", newClient.getBasePath()); + } + + @Test + public void testCreateAndGetPet() throws Exception { + Pet pet = createRandomPet(); + api.addPet(pet); + + Pet fetched = api.getPetById(pet.getId()); + assertNotNull(fetched); + assertEquals(pet.getId(), fetched.getId()); + assertNotNull(fetched.getCategory()); + assertEquals(fetched.getCategory().getName(), pet.getCategory().getName()); + } + + @Test + public void testUpdatePet() throws Exception { + Pet pet = createRandomPet(); + pet.setName("programmer"); + + api.updatePet(pet); + + Pet fetched = api.getPetById(pet.getId()); + assertNotNull(fetched); + assertEquals(pet.getId(), fetched.getId()); + assertNotNull(fetched.getCategory()); + assertEquals(fetched.getCategory().getName(), pet.getCategory().getName()); + } + + @Test + public void testFindPetsByStatus() throws Exception { + Pet pet = createRandomPet(); + pet.setName("programmer"); + pet.setStatus(Pet.StatusEnum.AVAILABLE); + + api.updatePet(pet); + + List pets = api.findPetsByStatus(Arrays.asList(new String[]{"available"})); + assertNotNull(pets); + + boolean found = false; + for (Pet fetched : pets) { + if (fetched.getId().equals(pet.getId())) { + found = true; + break; + } + } + + assertTrue(found); + } + + @Test + public void testFindPetsByTags() throws Exception { + Pet pet = createRandomPet(); + pet.setName("monster"); + pet.setStatus(Pet.StatusEnum.AVAILABLE); + + List tags = new ArrayList(); + Tag tag1 = new Tag(); + tag1.setName("friendly"); + tags.add(tag1); + pet.setTags(tags); + + api.updatePet(pet); + + List pets = api.findPetsByTags(Arrays.asList(new String[]{"friendly"})); + assertNotNull(pets); + + boolean found = false; + for (Pet fetched : pets) { + if (fetched.getId().equals(pet.getId())) { + found = true; + break; + } + } + assertTrue(found); + } + + @Test + public void testUpdatePetWithForm() throws Exception { + Pet pet = createRandomPet(); + pet.setName("frank"); + api.addPet(pet); + + Pet fetched = api.getPetById(pet.getId()); + + api.updatePetWithForm(fetched.getId(), "furt", null); + Pet updated = api.getPetById(fetched.getId()); + + assertEquals(updated.getName(), "furt"); + } + + @Test + public void testDeletePet() throws Exception { + Pet pet = createRandomPet(); + api.addPet(pet); + + Pet fetched = api.getPetById(pet.getId()); + api.deletePet(fetched.getId(), null); + + try { + fetched = api.getPetById(fetched.getId()); + fail("expected an error"); + } catch (Exception e) { +// assertEquals(404, e.getCode()); + } + } + + @Test + public void testUploadFile() throws Exception { + Pet pet = createRandomPet(); + api.addPet(pet); + + File file = new File("hello.txt"); + BufferedWriter writer = new BufferedWriter(new FileWriter(file)); + writer.write("Hello world!"); + writer.close(); + + api.uploadFile(pet.getId(), "a test file", new File(file.getAbsolutePath())); + } + + @Test + public void testEqualsAndHashCode() { + Pet pet1 = new Pet(); + Pet pet2 = new Pet(); + assertTrue(pet1.equals(pet2)); + assertTrue(pet2.equals(pet1)); + assertTrue(pet1.hashCode() == pet2.hashCode()); + assertTrue(pet1.equals(pet1)); + assertTrue(pet1.hashCode() == pet1.hashCode()); + + pet2.setName("really-happy"); + pet2.setPhotoUrls(Arrays.asList(new String[]{"http://foo.bar.com/1", "http://foo.bar.com/2"})); + assertFalse(pet1.equals(pet2)); + assertFalse(pet2.equals(pet1)); + assertFalse(pet1.hashCode() == (pet2.hashCode())); + assertTrue(pet2.equals(pet2)); + assertTrue(pet2.hashCode() == pet2.hashCode()); + + pet1.setName("really-happy"); + pet1.setPhotoUrls(Arrays.asList(new String[]{"http://foo.bar.com/1", "http://foo.bar.com/2"})); + assertTrue(pet1.equals(pet2)); + assertTrue(pet2.equals(pet1)); + assertTrue(pet1.hashCode() == pet2.hashCode()); + assertTrue(pet1.equals(pet1)); + assertTrue(pet1.hashCode() == pet1.hashCode()); + } + + private Pet createRandomPet() { + Pet pet = new Pet(); + pet.setId(System.currentTimeMillis()); + pet.setName("gorilla"); + + Category category = new Category(); + category.setName("really-happy"); + + pet.setCategory(category); + pet.setStatus(Pet.StatusEnum.AVAILABLE); + List photos = Arrays.asList(new String[]{"http://foo.bar.com/1", "http://foo.bar.com/2"}); + pet.setPhotoUrls(photos); + + return pet; + } +} \ No newline at end of file diff --git a/samples/client/petstore/java/feign/src/test/java/io/swagger/petstore/test/StoreApiTest.java b/samples/client/petstore/java/feign/src/test/java/io/swagger/petstore/test/StoreApiTest.java new file mode 100644 index 000000000000..060e73e5efd6 --- /dev/null +++ b/samples/client/petstore/java/feign/src/test/java/io/swagger/petstore/test/StoreApiTest.java @@ -0,0 +1,70 @@ +package io.swagger.petstore.test; + +import io.swagger.client.ApiException; + +import io.swagger.client.*; +import io.swagger.client.api.*; +import io.swagger.client.model.*; + +import java.util.Map; + +import org.junit.*; +import static org.junit.Assert.*; + +public class StoreApiTest { + ApiClient apiClient; + StoreApi api; + + @Before + public void setup() { + apiClient = new ApiClient(); + api = apiClient.buildClient(StoreApi.class); + } + + @Test + public void testGetInventory() throws Exception { + Map inventory = api.getInventory(); + assertTrue(inventory.keySet().size() > 0); + } + + @Test + public void testPlaceOrder() throws Exception { + Order order = createOrder(); + api.placeOrder(order); + + Order fetched = api.getOrderById(order.getId()); + assertEquals(order.getId(), fetched.getId()); + assertEquals(order.getPetId(), fetched.getPetId()); + assertEquals(order.getQuantity(), fetched.getQuantity()); + } + + @Test + public void testDeleteOrder() throws Exception { + Order order = createOrder(); + api.placeOrder(order); + + Order fetched = api.getOrderById(order.getId()); + assertEquals(fetched.getId(), order.getId()); + + api.deleteOrder(String.valueOf(order.getId())); + + try { + api.getOrderById(order.getId()); + // fail("expected an error"); + } catch (ApiException e) { + // ok + } + } + + private Order createOrder() { + Order order = new Order(); + order.setId(new Long(System.currentTimeMillis())); + order.setPetId(new Long(200)); + order.setQuantity(new Integer(13)); + order.setShipDate(new java.util.Date()); + order.setStatus(Order.StatusEnum.PLACED); + order.setComplete(true); + + return order; + } +} \ No newline at end of file diff --git a/samples/client/petstore/java/feign/src/test/java/io/swagger/petstore/test/UserApiTest.java b/samples/client/petstore/java/feign/src/test/java/io/swagger/petstore/test/UserApiTest.java new file mode 100644 index 000000000000..dc2d3ac17cac --- /dev/null +++ b/samples/client/petstore/java/feign/src/test/java/io/swagger/petstore/test/UserApiTest.java @@ -0,0 +1,85 @@ +package io.swagger.petstore.test; + +import io.swagger.client.ApiClient; +import io.swagger.client.api.*; +import io.swagger.client.model.*; + +import java.util.Arrays; + +import org.junit.*; +import static org.junit.Assert.*; + +public class UserApiTest { + ApiClient apiClient; + UserApi api; + + @Before + public void setup() { + apiClient = new ApiClient(); + api = apiClient.buildClient(UserApi.class); + } + + @Test + public void testCreateUser() throws Exception { + User user = createUser(); + + api.createUser(user); + + User fetched = api.getUserByName(user.getUsername()); + assertEquals(user.getId(), fetched.getId()); + } + + @Test + public void testCreateUsersWithArray() throws Exception { + User user1 = createUser(); + user1.setUsername("abc123"); + User user2 = createUser(); + user2.setUsername("123abc"); + + api.createUsersWithArrayInput(Arrays.asList(new User[]{user1, user2})); + + User fetched = api.getUserByName(user1.getUsername()); + assertEquals(user1.getId(), fetched.getId()); + } + + @Test + public void testCreateUsersWithList() throws Exception { + User user1 = createUser(); + user1.setUsername("abc123"); + User user2 = createUser(); + user2.setUsername("123abc"); + + api.createUsersWithListInput(Arrays.asList(new User[]{user1, user2})); + + User fetched = api.getUserByName(user1.getUsername()); + assertEquals(user1.getId(), fetched.getId()); + } + + @Test + public void testLoginUser() throws Exception { + User user = createUser(); + api.createUser(user); + + String token = api.loginUser(user.getUsername(), user.getPassword()); + assertTrue(token.startsWith("logged in user session:")); + } + + @Test + public void logoutUser() throws Exception { + api.logoutUser(); + } + + private User createUser() { + User user = new User(); + user.setId(System.currentTimeMillis()); + user.setUsername("fred" + user.getId()); + user.setFirstName("Fred"); + user.setLastName("Meyer"); + user.setEmail("fred@fredmeyer.com"); + user.setPassword("xxXXxx"); + user.setPhone("408-867-5309"); + user.setUserStatus(123); + + return user; + } +} \ No newline at end of file From 17230785083fcfd8e8bef3f23f460beeeddfd7eb Mon Sep 17 00:00:00 2001 From: David Kiss Date: Mon, 7 Dec 2015 22:34:38 -0500 Subject: [PATCH 18/71] added support in feign for binary uploads --- .../libraries/feign/FormAwareEncoder.mustache | 172 ++++++++++------- .../Java/libraries/feign/api.mustache | 8 +- samples/client/petstore/java/feign/README.md | 4 +- samples/client/petstore/java/feign/pom.xml | 4 +- .../petstore/java/feign/settings.gradle | 2 +- .../java/io/swagger/client/ApiClient.java | 2 +- .../io/swagger/client/FormAwareEncoder.java | 174 +++++++++++------- .../java/io/swagger/client/StringUtil.java | 2 +- .../java/io/swagger/client/api/PetApi.java | 26 ++- .../java/io/swagger/client/api/StoreApi.java | 16 +- .../java/io/swagger/client/api/UserApi.java | 24 +-- .../io/swagger/client/model/ApiResponse.java | 2 +- .../io/swagger/client/model/Category.java | 2 +- .../java/io/swagger/client/model/Order.java | 2 +- .../java/io/swagger/client/model/Pet.java | 2 +- .../java/io/swagger/client/model/Tag.java | 2 +- .../java/io/swagger/client/model/User.java | 2 +- .../swagger/petstore/test/StoreApiTest.java | 10 +- 18 files changed, 256 insertions(+), 200 deletions(-) diff --git a/modules/swagger-codegen/src/main/resources/Java/libraries/feign/FormAwareEncoder.mustache b/modules/swagger-codegen/src/main/resources/Java/libraries/feign/FormAwareEncoder.mustache index d0f026cced9a..822aad582d49 100644 --- a/modules/swagger-codegen/src/main/resources/Java/libraries/feign/FormAwareEncoder.mustache +++ b/modules/swagger-codegen/src/main/resources/Java/libraries/feign/FormAwareEncoder.mustache @@ -4,21 +4,31 @@ import java.io.*; import java.lang.reflect.Type; import java.net.URLEncoder; import java.net.URLConnection; +import java.nio.charset.Charset; import java.util.*; import java.text.DateFormat; import java.text.SimpleDateFormat; +import feign.codec.EncodeException; import feign.codec.Encoder; import feign.RequestTemplate; {{>generatedAnnotation}} public class FormAwareEncoder implements Encoder { + public static final String UTF_8 = "utf-8"; private static final String LINE_FEED = "\r\n"; + private static final String TWO_DASH = "--"; private static final String BOUNDARY = "----------------314159265358979323846"; + private byte[] lineFeedBytes; + private byte[] boundaryBytes; + private byte[] twoDashBytes; + private byte[] atBytes; + private byte[] eqBytes; + private final Encoder delegate; - private DateFormat dateFormat; + private final DateFormat dateFormat; public FormAwareEncoder(Encoder delegate) { this.delegate = delegate; @@ -28,93 +38,121 @@ public class FormAwareEncoder implements Encoder { // Use UTC as the default time zone. this.dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + try { + this.lineFeedBytes = LINE_FEED.getBytes(UTF_8); + this.boundaryBytes = BOUNDARY.getBytes(UTF_8); + this.twoDashBytes = TWO_DASH.getBytes(UTF_8); + this.atBytes = "&".getBytes(UTF_8); + this.eqBytes = "=".getBytes(UTF_8); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } } - public void encode(Object object, Type bodyType, RequestTemplate template) { + public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException { if (object instanceof Map) { - StringBuilder formParamBuilder = new StringBuilder(); - Map formParams = (Map) object; - boolean isMultiPart = isMultiPart(formParams); - for (Map.Entry param : formParams.entrySet()) { - String keyStr = param.getKey(); - if (param.getValue() instanceof File) { - addFilePart(formParamBuilder, keyStr, (File) param.getValue()); - } else { - String valueStr = parameterToString(param.getValue()); - if (isMultiPart) { - addMultiPartFormField(formParamBuilder, keyStr, valueStr); - } else { - addEncodedFormField(formParamBuilder, keyStr, valueStr); - } - } + try { + encodeFormParams(template, (Map) object); + } catch (IOException e) { + throw new EncodeException("Failed to create request", e); } - - if (isMultiPart) { - formParamBuilder.append(LINE_FEED); - formParamBuilder.append("--").append(BOUNDARY).append("--").append(LINE_FEED); - } - - String contentType = isMultiPart ? "multipart/form-data; boundary=" + BOUNDARY : "application/x-www-form-urlencoded"; - template.header("Content-type"); - template.header("Content-type", contentType); - template.header("MIME-Version", "1.0"); - template.body(formParamBuilder.toString()); } else { delegate.encode(object, bodyType, template); } } + private void encodeFormParams(RequestTemplate template, Map formParams) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + boolean isMultiPart = isMultiPart(formParams); + boolean isFirstField = true; + for (Map.Entry param : formParams.entrySet()) { + String keyStr = param.getKey(); + if (param.getValue() instanceof File) { + addFilePart(baos, keyStr, (File) param.getValue()); + } else { + String valueStr = parameterToString(param.getValue()); + if (isMultiPart) { + addMultiPartFormField(baos, keyStr, valueStr); + } else { + addEncodedFormField(baos, keyStr, valueStr, isFirstField); + isFirstField = false; + } + } + } + + if (isMultiPart) { + baos.write(lineFeedBytes); + baos.write(twoDashBytes); + baos.write(boundaryBytes); + baos.write(twoDashBytes); + baos.write(lineFeedBytes); + } + + String contentType = isMultiPart ? "multipart/form-data; boundary=" + BOUNDARY : "application/x-www-form-urlencoded"; + template.header("Content-type"); + template.header("Content-type", contentType); + template.header("MIME-Version", "1.0"); + template.body(baos.toByteArray(), Charset.forName(UTF_8)); + } + /* * Currently only supports text files */ - private void addFilePart(StringBuilder formParamBuilder, String fieldName, File uploadFile) { - try { - String fileName = uploadFile.getName(); - formParamBuilder.append("--").append(BOUNDARY).append(LINE_FEED); - formParamBuilder.append( - "Content-Disposition: form-data; name=\"" + fieldName - + "\"; filename=\"" + fileName + "\"") - .append(LINE_FEED); - formParamBuilder.append( - "Content-Type: " - + URLConnection.guessContentTypeFromName(fileName)) - .append(LINE_FEED); - formParamBuilder.append(LINE_FEED); + private void addFilePart(ByteArrayOutputStream baos, String fieldName, File uploadFile) throws IOException { + String fileName = uploadFile.getName(); + baos.write(twoDashBytes); + baos.write(boundaryBytes); + baos.write(lineFeedBytes); - BufferedReader reader = new BufferedReader(new FileReader(uploadFile)); - String line = ""; - while ((line = reader.readLine()) != null) { - formParamBuilder.append(line).append(LINE_FEED); - } + String contentDisposition = "Content-Disposition: form-data; name=\"" + fieldName + + "\"; filename=\"" + fileName + "\""; + baos.write(contentDisposition.getBytes(UTF_8)); + baos.write(lineFeedBytes); + String contentType = "Content-Type: " + URLConnection.guessContentTypeFromName(fileName); + baos.write(contentType.getBytes(UTF_8)); + baos.write(lineFeedBytes); + baos.write(lineFeedBytes); - formParamBuilder.append(LINE_FEED); - } catch (IOException e) { - e.printStackTrace(); + BufferedReader reader = new BufferedReader(new FileReader(uploadFile)); + InputStream input = new FileInputStream(uploadFile); + byte[] bytes = new byte[4096]; + int len = bytes.length; + while ((len = input.read(bytes)) != -1) { + baos.write(bytes, 0, len); + baos.write(lineFeedBytes); } + + baos.write(lineFeedBytes); } - private void addEncodedFormField(StringBuilder formParamBuilder, String name, String value) { - if (formParamBuilder.length() > 0) { - formParamBuilder.append("&"); + private void addEncodedFormField(ByteArrayOutputStream baos, String name, String value, boolean isFirstField) throws IOException { + if (!isFirstField) { + baos.write(atBytes); } - try { - formParamBuilder.append(URLEncoder.encode(name, "utf8")) - .append("=") - .append(URLEncoder.encode(value, "utf8")); - } catch (UnsupportedEncodingException e) { - // move on to next - } + String encodedName = URLEncoder.encode(name, UTF_8); + String encodedValue = URLEncoder.encode(value, UTF_8); + baos.write(encodedName.getBytes(UTF_8)); + baos.write("=".getBytes(UTF_8)); + baos.write(encodedValue.getBytes(UTF_8)); } - private void addMultiPartFormField(StringBuilder formParamBuilder, String name, String value) { - formParamBuilder.append("--").append(BOUNDARY).append(LINE_FEED); - formParamBuilder.append("Content-Disposition: form-data; name=\"" + name + "\"") - .append(LINE_FEED); - formParamBuilder.append("Content-Type: text/plain; charset=utf-8").append( - LINE_FEED); - formParamBuilder.append(LINE_FEED); - formParamBuilder.append(value).append(LINE_FEED); + private void addMultiPartFormField(ByteArrayOutputStream baos, String name, String value) throws IOException { + baos.write(twoDashBytes); + baos.write(boundaryBytes); + baos.write(lineFeedBytes); + + String contentDisposition = "Content-Disposition: form-data; name=\"" + name + "\""; + String contentType = "Content-Type: text/plain; charset=utf-8"; + + baos.write(contentDisposition.getBytes(UTF_8)); + baos.write(lineFeedBytes); + baos.write(contentType.getBytes(UTF_8)); + baos.write(lineFeedBytes); + baos.write(lineFeedBytes); + baos.write(value.getBytes(UTF_8)); + baos.write(lineFeedBytes); } private boolean isMultiPart(Map formParams) { diff --git a/modules/swagger-codegen/src/main/resources/Java/libraries/feign/api.mustache b/modules/swagger-codegen/src/main/resources/Java/libraries/feign/api.mustache index 201068061022..30c8a793914e 100644 --- a/modules/swagger-codegen/src/main/resources/Java/libraries/feign/api.mustache +++ b/modules/swagger-codegen/src/main/resources/Java/libraries/feign/api.mustache @@ -1,10 +1,6 @@ package {{package}}; -import {{invokerPackage}}.ApiException; import {{invokerPackage}}.ApiClient; -import {{invokerPackage}}.Configuration; -import {{invokerPackage}}.Pair; -import {{invokerPackage}}.TypeRef; {{#imports}}import {{import}}; {{/imports}} @@ -14,7 +10,7 @@ import {{invokerPackage}}.TypeRef; import feign.*; {{>generatedAnnotation}} -public interface {{classname}} extends {{invokerPackage}}.ApiClient.Api { +public interface {{classname}} extends ApiClient.Api { {{#operations}}{{#operation}} /** @@ -30,7 +26,7 @@ public interface {{classname}} extends {{invokerPackage}}.ApiClient.Api { "{{paramName}}: {{=<% %>=}}{<%paramName%>}<%={{ }}=%>"{{#hasMore}}, {{/hasMore}}{{/headerParams}} }) - {{#returnType}}{{{returnType}}} {{/returnType}}{{^returnType}}void {{/returnType}}{{nickname}}({{#allParams}}{{^vendorExtensions.x-isBody}}@Param("{{paramName}}") {{/vendorExtensions.x-isBody}}{{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) throws ApiException; + {{#returnType}}{{{returnType}}} {{/returnType}}{{^returnType}}void {{/returnType}}{{nickname}}({{#allParams}}{{^vendorExtensions.x-isBody}}@Param("{{paramName}}") {{/vendorExtensions.x-isBody}}{{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}); {{/operation}} {{/operations}} } diff --git a/samples/client/petstore/java/feign/README.md b/samples/client/petstore/java/feign/README.md index 3ca7abfb5573..8afc37518fc7 100644 --- a/samples/client/petstore/java/feign/README.md +++ b/samples/client/petstore/java/feign/README.md @@ -1,4 +1,4 @@ -# swagger-petstore-feign +# swagger-java-client ## Requirements @@ -25,7 +25,7 @@ After the client libarary is installed/deployed, you can use it in your Maven pr ```xml io.swagger - swagger-petstore-feign + swagger-java-client 1.0.0 compile diff --git a/samples/client/petstore/java/feign/pom.xml b/samples/client/petstore/java/feign/pom.xml index 5f7e95518625..967bdabcc6bc 100644 --- a/samples/client/petstore/java/feign/pom.xml +++ b/samples/client/petstore/java/feign/pom.xml @@ -2,9 +2,9 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 4.0.0 io.swagger - swagger-petstore-feign + swagger-java-client jar - swagger-petstore-feign + swagger-java-client 1.0.0 scm:git:git@github.com:swagger-api/swagger-mustache.git diff --git a/samples/client/petstore/java/feign/settings.gradle b/samples/client/petstore/java/feign/settings.gradle index a25109c126eb..55640f75122e 100644 --- a/samples/client/petstore/java/feign/settings.gradle +++ b/samples/client/petstore/java/feign/settings.gradle @@ -1 +1 @@ -rootProject.name = "swagger-petstore-feign" \ No newline at end of file +rootProject.name = "swagger-java-client" \ No newline at end of file diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/ApiClient.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/ApiClient.java index e486c713a923..001d05f49f05 100644 --- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/ApiClient.java +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/ApiClient.java @@ -8,7 +8,7 @@ import feign.jackson.JacksonDecoder; import feign.jackson.JacksonEncoder; import feign.slf4j.Slf4jLogger; -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T01:11:21.159-05:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T22:27:06.680-05:00") public class ApiClient { public interface Api {} diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/FormAwareEncoder.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/FormAwareEncoder.java index 3ec3c6b92747..3f0230a406a8 100644 --- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/FormAwareEncoder.java +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/FormAwareEncoder.java @@ -4,21 +4,31 @@ import java.io.*; import java.lang.reflect.Type; import java.net.URLEncoder; import java.net.URLConnection; +import java.nio.charset.Charset; import java.util.*; import java.text.DateFormat; import java.text.SimpleDateFormat; +import feign.codec.EncodeException; import feign.codec.Encoder; import feign.RequestTemplate; -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T01:11:21.159-05:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T22:27:06.680-05:00") public class FormAwareEncoder implements Encoder { + public static final String UTF_8 = "utf-8"; private static final String LINE_FEED = "\r\n"; + private static final String TWO_DASH = "--"; private static final String BOUNDARY = "----------------314159265358979323846"; + private byte[] lineFeedBytes; + private byte[] boundaryBytes; + private byte[] twoDashBytes; + private byte[] atBytes; + private byte[] eqBytes; + private final Encoder delegate; - private DateFormat dateFormat; + private final DateFormat dateFormat; public FormAwareEncoder(Encoder delegate) { this.delegate = delegate; @@ -28,93 +38,121 @@ public class FormAwareEncoder implements Encoder { // Use UTC as the default time zone. this.dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + try { + this.lineFeedBytes = LINE_FEED.getBytes(UTF_8); + this.boundaryBytes = BOUNDARY.getBytes(UTF_8); + this.twoDashBytes = TWO_DASH.getBytes(UTF_8); + this.atBytes = "&".getBytes(UTF_8); + this.eqBytes = "=".getBytes(UTF_8); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } } - public void encode(Object object, Type bodyType, RequestTemplate template) { + public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException { if (object instanceof Map) { - StringBuilder formParamBuilder = new StringBuilder(); - Map formParams = (Map) object; - boolean isMultiPart = isMultiPart(formParams); - for (Map.Entry param : formParams.entrySet()) { - String keyStr = param.getKey(); - if (param.getValue() instanceof File) { - addFilePart(formParamBuilder, keyStr, (File) param.getValue()); - } else { - String valueStr = parameterToString(param.getValue()); - if (isMultiPart) { - addMultiPartFormField(formParamBuilder, keyStr, valueStr); - } else { - addEncodedFormField(formParamBuilder, keyStr, valueStr); - } - } + try { + encodeFormParams(template, (Map) object); + } catch (IOException e) { + throw new EncodeException("Failed to create request", e); } - - if (isMultiPart) { - formParamBuilder.append(LINE_FEED); - formParamBuilder.append("--").append(BOUNDARY).append("--").append(LINE_FEED); - } - - String contentType = isMultiPart ? "multipart/form-data; boundary=" + BOUNDARY : "application/x-www-form-urlencoded"; - template.header("Content-type"); - template.header("Content-type", contentType); - template.header("MIME-Version", "1.0"); - template.body(formParamBuilder.toString()); } else { delegate.encode(object, bodyType, template); } } + private void encodeFormParams(RequestTemplate template, Map formParams) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + boolean isMultiPart = isMultiPart(formParams); + boolean isFirstField = true; + for (Map.Entry param : formParams.entrySet()) { + String keyStr = param.getKey(); + if (param.getValue() instanceof File) { + addFilePart(baos, keyStr, (File) param.getValue()); + } else { + String valueStr = parameterToString(param.getValue()); + if (isMultiPart) { + addMultiPartFormField(baos, keyStr, valueStr); + } else { + addEncodedFormField(baos, keyStr, valueStr, isFirstField); + isFirstField = false; + } + } + } + + if (isMultiPart) { + baos.write(lineFeedBytes); + baos.write(twoDashBytes); + baos.write(boundaryBytes); + baos.write(twoDashBytes); + baos.write(lineFeedBytes); + } + + String contentType = isMultiPart ? "multipart/form-data; boundary=" + BOUNDARY : "application/x-www-form-urlencoded"; + template.header("Content-type"); + template.header("Content-type", contentType); + template.header("MIME-Version", "1.0"); + template.body(baos.toByteArray(), Charset.forName(UTF_8)); + } + /* * Currently only supports text files */ - private void addFilePart(StringBuilder formParamBuilder, String fieldName, File uploadFile) { - try { - String fileName = uploadFile.getName(); - formParamBuilder.append("--").append(BOUNDARY).append(LINE_FEED); - formParamBuilder.append( - "Content-Disposition: form-data; name=\"" + fieldName - + "\"; filename=\"" + fileName + "\"") - .append(LINE_FEED); - formParamBuilder.append( - "Content-Type: " - + URLConnection.guessContentTypeFromName(fileName)) - .append(LINE_FEED); - formParamBuilder.append(LINE_FEED); + private void addFilePart(ByteArrayOutputStream baos, String fieldName, File uploadFile) throws IOException { + String fileName = uploadFile.getName(); + baos.write(twoDashBytes); + baos.write(boundaryBytes); + baos.write(lineFeedBytes); - BufferedReader reader = new BufferedReader(new FileReader(uploadFile)); - String line = ""; - while ((line = reader.readLine()) != null) { - formParamBuilder.append(line).append(LINE_FEED); - } + String contentDisposition = "Content-Disposition: form-data; name=\"" + fieldName + + "\"; filename=\"" + fileName + "\""; + baos.write(contentDisposition.getBytes(UTF_8)); + baos.write(lineFeedBytes); + String contentType = "Content-Type: " + URLConnection.guessContentTypeFromName(fileName); + baos.write(contentType.getBytes(UTF_8)); + baos.write(lineFeedBytes); + baos.write(lineFeedBytes); - formParamBuilder.append(LINE_FEED); - } catch (IOException e) { - e.printStackTrace(); + BufferedReader reader = new BufferedReader(new FileReader(uploadFile)); + InputStream input = new FileInputStream(uploadFile); + byte[] bytes = new byte[4096]; + int len = bytes.length; + while ((len = input.read(bytes)) != -1) { + baos.write(bytes, 0, len); + baos.write(lineFeedBytes); } + + baos.write(lineFeedBytes); } - private void addEncodedFormField(StringBuilder formParamBuilder, String name, String value) { - if (formParamBuilder.length() > 0) { - formParamBuilder.append("&"); + private void addEncodedFormField(ByteArrayOutputStream baos, String name, String value, boolean isFirstField) throws IOException { + if (!isFirstField) { + baos.write(atBytes); } - try { - formParamBuilder.append(URLEncoder.encode(name, "utf8")) - .append("=") - .append(URLEncoder.encode(value, "utf8")); - } catch (UnsupportedEncodingException e) { - // move on to next - } + String encodedName = URLEncoder.encode(name, UTF_8); + String encodedValue = URLEncoder.encode(value, UTF_8); + baos.write(encodedName.getBytes(UTF_8)); + baos.write("=".getBytes(UTF_8)); + baos.write(encodedValue.getBytes(UTF_8)); } - private void addMultiPartFormField(StringBuilder formParamBuilder, String name, String value) { - formParamBuilder.append("--").append(BOUNDARY).append(LINE_FEED); - formParamBuilder.append("Content-Disposition: form-data; name=\"" + name + "\"") - .append(LINE_FEED); - formParamBuilder.append("Content-Type: text/plain; charset=utf-8").append( - LINE_FEED); - formParamBuilder.append(LINE_FEED); - formParamBuilder.append(value).append(LINE_FEED); + private void addMultiPartFormField(ByteArrayOutputStream baos, String name, String value) throws IOException { + baos.write(twoDashBytes); + baos.write(boundaryBytes); + baos.write(lineFeedBytes); + + String contentDisposition = "Content-Disposition: form-data; name=\"" + name + "\""; + String contentType = "Content-Type: text/plain; charset=utf-8"; + + baos.write(contentDisposition.getBytes(UTF_8)); + baos.write(lineFeedBytes); + baos.write(contentType.getBytes(UTF_8)); + baos.write(lineFeedBytes); + baos.write(lineFeedBytes); + baos.write(value.getBytes(UTF_8)); + baos.write(lineFeedBytes); } private boolean isMultiPart(Map formParams) { diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/StringUtil.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/StringUtil.java index 82b8d8afa0bf..db6460490faa 100644 --- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/StringUtil.java +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/StringUtil.java @@ -1,6 +1,6 @@ package io.swagger.client; -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-01T16:10:23.565+08:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T22:27:06.680-05:00") public class StringUtil { /** * Check if the given array contains the given value (with case-insensitive comparison). diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/PetApi.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/PetApi.java index e2e7e6ce742a..caa70b4260af 100644 --- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/PetApi.java +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/PetApi.java @@ -1,20 +1,18 @@ package io.swagger.client.api; -import io.swagger.client.ApiException; import io.swagger.client.ApiClient; -import io.swagger.client.Configuration; -import io.swagger.client.Pair; -import io.swagger.client.TypeRef; import io.swagger.client.model.Pet; import java.io.File; import io.swagger.client.model.ApiResponse; + import java.util.*; + import feign.*; -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T01:11:21.159-05:00") -public interface PetApi extends io.swagger.client.ApiClient.Api { +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T22:27:06.680-05:00") +public interface PetApi extends ApiClient.Api { /** @@ -28,7 +26,7 @@ public interface PetApi extends io.swagger.client.ApiClient.Api { "Content-type: application/json", "Accepts: application/json", }) - void updatePet(Pet body) throws ApiException; + void updatePet(Pet body); /** * Add a new pet to the store @@ -41,7 +39,7 @@ public interface PetApi extends io.swagger.client.ApiClient.Api { "Content-type: application/json", "Accepts: application/json", }) - void addPet(Pet body) throws ApiException; + void addPet(Pet body); /** * Finds Pets by status @@ -54,7 +52,7 @@ public interface PetApi extends io.swagger.client.ApiClient.Api { "Content-type: application/json", "Accepts: application/json", }) - List findPetsByStatus(@Param("status") List status) throws ApiException; + List findPetsByStatus(@Param("status") List status); /** * Finds Pets by tags @@ -67,7 +65,7 @@ public interface PetApi extends io.swagger.client.ApiClient.Api { "Content-type: application/json", "Accepts: application/json", }) - List findPetsByTags(@Param("tags") List tags) throws ApiException; + List findPetsByTags(@Param("tags") List tags); /** * Find pet by ID @@ -80,7 +78,7 @@ public interface PetApi extends io.swagger.client.ApiClient.Api { "Content-type: application/json", "Accepts: application/json", }) - Pet getPetById(@Param("petId") Long petId) throws ApiException; + Pet getPetById(@Param("petId") Long petId); /** * Updates a pet in the store with form data @@ -95,7 +93,7 @@ public interface PetApi extends io.swagger.client.ApiClient.Api { "Content-type: application/x-www-form-urlencoded", "Accepts: application/json", }) - void updatePetWithForm(@Param("petId") Long petId, @Param("name") String name, @Param("status") String status) throws ApiException; + void updatePetWithForm(@Param("petId") Long petId, @Param("name") String name, @Param("status") String status); /** * Deletes a pet @@ -110,7 +108,7 @@ public interface PetApi extends io.swagger.client.ApiClient.Api { "Accepts: application/json", "apiKey: {apiKey}" }) - void deletePet(@Param("petId") Long petId, @Param("apiKey") String apiKey) throws ApiException; + void deletePet(@Param("petId") Long petId, @Param("apiKey") String apiKey); /** * uploads an image @@ -125,7 +123,7 @@ public interface PetApi extends io.swagger.client.ApiClient.Api { "Content-type: multipart/form-data", "Accepts: application/json", }) - ApiResponse uploadFile(@Param("petId") Long petId, @Param("additionalMetadata") String additionalMetadata, @Param("file") File file) throws ApiException; + ApiResponse uploadFile(@Param("petId") Long petId, @Param("additionalMetadata") String additionalMetadata, @Param("file") File file); } diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/StoreApi.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/StoreApi.java index 87321de5df75..a022f684a4e2 100644 --- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/StoreApi.java +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/StoreApi.java @@ -1,10 +1,6 @@ package io.swagger.client.api; -import io.swagger.client.ApiException; import io.swagger.client.ApiClient; -import io.swagger.client.Configuration; -import io.swagger.client.Pair; -import io.swagger.client.TypeRef; import java.util.Map; import io.swagger.client.model.Order; @@ -14,8 +10,8 @@ import java.util.*; import feign.*; -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T01:11:21.159-05:00") -public interface StoreApi extends io.swagger.client.ApiClient.Api { +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T22:27:06.680-05:00") +public interface StoreApi extends ApiClient.Api { /** @@ -28,7 +24,7 @@ public interface StoreApi extends io.swagger.client.ApiClient.Api { "Content-type: application/json", "Accepts: application/json", }) - Map getInventory() throws ApiException; + Map getInventory(); /** * Place an order for a pet @@ -41,7 +37,7 @@ public interface StoreApi extends io.swagger.client.ApiClient.Api { "Content-type: application/json", "Accepts: application/json", }) - Order placeOrder(Order body) throws ApiException; + Order placeOrder(Order body); /** * Find purchase order by ID @@ -54,7 +50,7 @@ public interface StoreApi extends io.swagger.client.ApiClient.Api { "Content-type: application/json", "Accepts: application/json", }) - Order getOrderById(@Param("orderId") Long orderId) throws ApiException; + Order getOrderById(@Param("orderId") Long orderId); /** * Delete purchase order by ID @@ -67,7 +63,7 @@ public interface StoreApi extends io.swagger.client.ApiClient.Api { "Content-type: application/json", "Accepts: application/json", }) - void deleteOrder(@Param("orderId") String orderId) throws ApiException; + void deleteOrder(@Param("orderId") String orderId); } diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/UserApi.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/UserApi.java index 070ca861818c..b2bac15d873f 100644 --- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/UserApi.java +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/UserApi.java @@ -1,10 +1,6 @@ package io.swagger.client.api; -import io.swagger.client.ApiException; import io.swagger.client.ApiClient; -import io.swagger.client.Configuration; -import io.swagger.client.Pair; -import io.swagger.client.TypeRef; import io.swagger.client.model.User; import java.util.*; @@ -14,8 +10,8 @@ import java.util.*; import feign.*; -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T01:11:21.159-05:00") -public interface UserApi extends io.swagger.client.ApiClient.Api { +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T22:27:06.680-05:00") +public interface UserApi extends ApiClient.Api { /** @@ -29,7 +25,7 @@ public interface UserApi extends io.swagger.client.ApiClient.Api { "Content-type: application/json", "Accepts: application/json", }) - void createUser(User body) throws ApiException; + void createUser(User body); /** * Creates list of users with given input array @@ -42,7 +38,7 @@ public interface UserApi extends io.swagger.client.ApiClient.Api { "Content-type: application/json", "Accepts: application/json", }) - void createUsersWithArrayInput(List body) throws ApiException; + void createUsersWithArrayInput(List body); /** * Creates list of users with given input array @@ -55,7 +51,7 @@ public interface UserApi extends io.swagger.client.ApiClient.Api { "Content-type: application/json", "Accepts: application/json", }) - void createUsersWithListInput(List body) throws ApiException; + void createUsersWithListInput(List body); /** * Logs user into the system @@ -69,7 +65,7 @@ public interface UserApi extends io.swagger.client.ApiClient.Api { "Content-type: application/json", "Accepts: application/json", }) - String loginUser(@Param("username") String username, @Param("password") String password) throws ApiException; + String loginUser(@Param("username") String username, @Param("password") String password); /** * Logs out current logged in user session @@ -81,7 +77,7 @@ public interface UserApi extends io.swagger.client.ApiClient.Api { "Content-type: application/json", "Accepts: application/json", }) - void logoutUser() throws ApiException; + void logoutUser(); /** * Get user by user name @@ -94,7 +90,7 @@ public interface UserApi extends io.swagger.client.ApiClient.Api { "Content-type: application/json", "Accepts: application/json", }) - User getUserByName(@Param("username") String username) throws ApiException; + User getUserByName(@Param("username") String username); /** * Updated user @@ -108,7 +104,7 @@ public interface UserApi extends io.swagger.client.ApiClient.Api { "Content-type: application/json", "Accepts: application/json", }) - void updateUser(@Param("username") String username, User body) throws ApiException; + void updateUser(@Param("username") String username, User body); /** * Delete user @@ -121,7 +117,7 @@ public interface UserApi extends io.swagger.client.ApiClient.Api { "Content-type: application/json", "Accepts: application/json", }) - void deleteUser(@Param("username") String username) throws ApiException; + void deleteUser(@Param("username") String username); } diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/ApiResponse.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/ApiResponse.java index f06d10acff27..4843a51e9880 100644 --- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/ApiResponse.java +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/ApiResponse.java @@ -12,7 +12,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; @ApiModel(description = "") -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T01:11:21.159-05:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T22:27:06.680-05:00") public class ApiResponse { private Integer code = null; diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Category.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Category.java index 8edf7db00513..a414345dd637 100644 --- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Category.java +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Category.java @@ -12,7 +12,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; @ApiModel(description = "") -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T01:11:21.159-05:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T22:27:06.680-05:00") public class Category { private Long id = null; diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Order.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Order.java index a057e4899f02..4f045ca04101 100644 --- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Order.java +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Order.java @@ -13,7 +13,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; @ApiModel(description = "") -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T01:11:21.159-05:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T22:27:06.680-05:00") public class Order { private Long id = null; diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Pet.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Pet.java index a844cfa8a836..4029fc4362ef 100644 --- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Pet.java +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Pet.java @@ -15,7 +15,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; @ApiModel(description = "") -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T01:11:21.159-05:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T22:27:06.680-05:00") public class Pet { private Long id = null; diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Tag.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Tag.java index 7995cbcaa9c6..2c3b0132bc6b 100644 --- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Tag.java +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Tag.java @@ -12,7 +12,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; @ApiModel(description = "") -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T01:11:21.159-05:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T22:27:06.680-05:00") public class Tag { private Long id = null; diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/User.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/User.java index d0d004b8c118..a8e902dd21ff 100644 --- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/User.java +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/User.java @@ -12,7 +12,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; @ApiModel(description = "") -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T01:11:21.159-05:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T22:27:06.680-05:00") public class User { private Long id = null; diff --git a/samples/client/petstore/java/feign/src/test/java/io/swagger/petstore/test/StoreApiTest.java b/samples/client/petstore/java/feign/src/test/java/io/swagger/petstore/test/StoreApiTest.java index 060e73e5efd6..b91c391e9918 100644 --- a/samples/client/petstore/java/feign/src/test/java/io/swagger/petstore/test/StoreApiTest.java +++ b/samples/client/petstore/java/feign/src/test/java/io/swagger/petstore/test/StoreApiTest.java @@ -1,7 +1,5 @@ package io.swagger.petstore.test; -import io.swagger.client.ApiException; - import io.swagger.client.*; import io.swagger.client.api.*; import io.swagger.client.model.*; @@ -48,12 +46,8 @@ public class StoreApiTest { api.deleteOrder(String.valueOf(order.getId())); - try { - api.getOrderById(order.getId()); - // fail("expected an error"); - } catch (ApiException e) { - // ok - } + api.getOrderById(order.getId()); +// fail("expected an error"); } private Order createOrder() { From 4b656c516f40ab86274d8e7f9305e5f5b358475d Mon Sep 17 00:00:00 2001 From: wing328 Date: Tue, 8 Dec 2015 15:59:46 +0800 Subject: [PATCH 19/71] add default value to php model --- .../codegen/languages/PhpClientCodegen.java | 56 ++++++++++++++++--- .../src/main/resources/php/model.mustache | 2 +- .../io/swagger/codegen/php/PhpModelTest.java | 8 +-- 3 files changed, 53 insertions(+), 13 deletions(-) diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/PhpClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/PhpClientCodegen.java index 56df40219f5c..c712374f4241 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/PhpClientCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/PhpClientCodegen.java @@ -6,10 +6,7 @@ import io.swagger.codegen.CodegenConstants; import io.swagger.codegen.CodegenType; import io.swagger.codegen.DefaultCodegen; import io.swagger.codegen.SupportingFile; -import io.swagger.models.properties.ArrayProperty; -import io.swagger.models.properties.MapProperty; -import io.swagger.models.properties.Property; -import io.swagger.models.properties.RefProperty; +import io.swagger.models.properties.*; import java.io.File; import java.util.Arrays; @@ -276,10 +273,6 @@ public class PhpClientCodegen extends DefaultCodegen implements CodegenConfig { return toModelName(type); } - public String toDefaultValue(Property p) { - return "null"; - } - public void setInvokerPackage(String invokerPackage) { this.invokerPackage = invokerPackage; } @@ -377,4 +370,51 @@ public class PhpClientCodegen extends DefaultCodegen implements CodegenConfig { return camelize(sanitizeName(operationId), true); } + /** + * Return the default value of the property + * + * @param p Swagger property object + * @return string presentation of the default value of the property + */ + @Override + public String toDefaultValue(Property p) { + if (p instanceof StringProperty) { + StringProperty dp = (StringProperty) p; + if (dp.getDefault() != null) { + return "'" + dp.getDefault().toString() + "'"; + } + } else if (p instanceof BooleanProperty) { + BooleanProperty dp = (BooleanProperty) p; + if (dp.getDefault() != null) { + return dp.getDefault().toString(); + } + } else if (p instanceof DateProperty) { + // TODO + } else if (p instanceof DateTimeProperty) { + // TODO + } else if (p instanceof DoubleProperty) { + DoubleProperty dp = (DoubleProperty) p; + if (dp.getDefault() != null) { + return dp.getDefault().toString(); + } + } else if (p instanceof FloatProperty) { + FloatProperty dp = (FloatProperty) p; + if (dp.getDefault() != null) { + return dp.getDefault().toString(); + } + } else if (p instanceof IntegerProperty) { + IntegerProperty dp = (IntegerProperty) p; + if (dp.getDefault() != null) { + return dp.getDefault().toString(); + } + } else if (p instanceof LongProperty) { + LongProperty dp = (LongProperty) p; + if (dp.getDefault() != null) { + return dp.getDefault().toString(); + } + } + + return null; + } + } diff --git a/modules/swagger-codegen/src/main/resources/php/model.mustache b/modules/swagger-codegen/src/main/resources/php/model.mustache index 861673982f22..66cabf0122b9 100644 --- a/modules/swagger-codegen/src/main/resources/php/model.mustache +++ b/modules/swagger-codegen/src/main/resources/php/model.mustache @@ -89,7 +89,7 @@ class {{classname}} implements ArrayAccess * ${{name}} {{#description}}{{{description}}}{{/description}} * @var {{datatype}} */ - protected ${{name}}; + protected ${{name}}{{#defaultValue}} = {{{defaultValue}}}{{/defaultValue}}; {{/vars}} /** diff --git a/modules/swagger-codegen/src/test/java/io/swagger/codegen/php/PhpModelTest.java b/modules/swagger-codegen/src/test/java/io/swagger/codegen/php/PhpModelTest.java index 52ca64f2f596..79da2d2ccda4 100644 --- a/modules/swagger-codegen/src/test/java/io/swagger/codegen/php/PhpModelTest.java +++ b/modules/swagger-codegen/src/test/java/io/swagger/codegen/php/PhpModelTest.java @@ -42,7 +42,7 @@ public class PhpModelTest { Assert.assertEquals(property1.baseName, "id"); Assert.assertEquals(property1.datatype, "int"); Assert.assertEquals(property1.name, "id"); - Assert.assertEquals(property1.defaultValue, "null"); + Assert.assertEquals(property1.defaultValue, null); Assert.assertEquals(property1.baseType, "int"); Assert.assertTrue(property1.hasMore); Assert.assertTrue(property1.required); @@ -53,7 +53,7 @@ public class PhpModelTest { Assert.assertEquals(property2.baseName, "name"); Assert.assertEquals(property2.datatype, "string"); Assert.assertEquals(property2.name, "name"); - Assert.assertEquals(property2.defaultValue, "null"); + Assert.assertEquals(property2.defaultValue, null); Assert.assertEquals(property2.baseType, "string"); Assert.assertTrue(property2.hasMore); Assert.assertTrue(property2.required); @@ -65,7 +65,7 @@ public class PhpModelTest { Assert.assertEquals(property3.complexType, "\\DateTime"); Assert.assertEquals(property3.datatype, "\\DateTime"); Assert.assertEquals(property3.name, "created_at"); - Assert.assertEquals(property3.defaultValue, "null"); + Assert.assertEquals(property3.defaultValue, null); Assert.assertEquals(property3.baseType, "\\DateTime"); Assert.assertNull(property3.hasMore); Assert.assertNull(property3.required); @@ -92,7 +92,7 @@ public class PhpModelTest { Assert.assertEquals(property1.baseName, "id"); Assert.assertEquals(property1.datatype, "int"); Assert.assertEquals(property1.name, "id"); - Assert.assertEquals(property1.defaultValue, "null"); + Assert.assertEquals(property1.defaultValue, null); Assert.assertEquals(property1.baseType, "int"); Assert.assertTrue(property1.hasMore); Assert.assertTrue(property1.required); From a01dfb693bf267a88f6ceb3532d458cfc52af94a Mon Sep 17 00:00:00 2001 From: Mateusz Mackowiak Date: Tue, 8 Dec 2015 18:52:59 +0100 Subject: [PATCH 20/71] Support for extended 'application/json' HeaderAccept types --- .../resources/objc/ApiClient-body.mustache | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/modules/swagger-codegen/src/main/resources/objc/ApiClient-body.mustache b/modules/swagger-codegen/src/main/resources/objc/ApiClient-body.mustache index d1908e5d2f11..0c23c8004694 100644 --- a/modules/swagger-codegen/src/main/resources/objc/ApiClient-body.mustache +++ b/modules/swagger-codegen/src/main/resources/objc/ApiClient-body.mustache @@ -128,24 +128,22 @@ static void (^reachabilityChangeBlock)(int); /* * Detect `Accept` from accepts */ -+ (NSString *) selectHeaderAccept:(NSArray *)accepts -{ ++ (NSString *) selectHeaderAccept:(NSArray *)accepts { if (accepts == nil || [accepts count] == 0) { return @""; } - NSMutableArray *lowerAccepts = [[NSMutableArray alloc] initWithCapacity:[accepts count]]; - [accepts enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { - [lowerAccepts addObject:[obj lowercaseString]]; - }]; - - - if ([lowerAccepts containsObject:@"application/json"]) { - return @"application/json"; + for (NSString *string in accepts) { + NSString * lowerAccept = [string lowercaseString]; + if([lowerAccept containsString:@"application/json"]) { + return @"application/json"; + } + [lowerAccepts addObject:lowerAccept]; } - else { - return [lowerAccepts componentsJoinedByString:@", "]; + if(lowerAccepts.count == 1){ + return [lowerAccepts firstObject]; } + return [lowerAccepts componentsJoinedByString:@", "]; } /* From 21bd4fbbc1d4018e5e5b0fe57fce19a3a065aa64 Mon Sep 17 00:00:00 2001 From: xhh Date: Tue, 8 Dec 2015 17:56:06 +0800 Subject: [PATCH 21/71] Add default value to Ruby model --- .../codegen/languages/RubyClientCodegen.java | 45 ++++++++++++++++--- .../src/main/resources/ruby/model.mustache | 6 ++- .../ruby/lib/petstore/models/category.rb | 2 +- .../ruby/lib/petstore/models/order.rb | 2 +- .../petstore/ruby/lib/petstore/models/pet.rb | 2 +- .../petstore/ruby/lib/petstore/models/tag.rb | 2 +- .../petstore/ruby/lib/petstore/models/user.rb | 2 +- 7 files changed, 47 insertions(+), 14 deletions(-) diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/RubyClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/RubyClientCodegen.java index f30b2ef8b85a..2fd6d8d8bc09 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/RubyClientCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/RubyClientCodegen.java @@ -6,9 +6,7 @@ import io.swagger.codegen.CodegenConstants; import io.swagger.codegen.CodegenType; import io.swagger.codegen.DefaultCodegen; import io.swagger.codegen.SupportingFile; -import io.swagger.models.properties.ArrayProperty; -import io.swagger.models.properties.MapProperty; -import io.swagger.models.properties.Property; +import io.swagger.models.properties.*; import java.io.File; import java.util.Arrays; @@ -186,6 +184,43 @@ public class RubyClientCodegen extends DefaultCodegen implements CodegenConfig { return super.getTypeDeclaration(p); } + @Override + public String toDefaultValue(Property p) { + if (p instanceof IntegerProperty) { + IntegerProperty dp = (IntegerProperty) p; + if (dp.getDefault() != null) { + return dp.getDefault().toString(); + } + } else if (p instanceof LongProperty) { + LongProperty dp = (LongProperty) p; + if (dp.getDefault() != null) { + return dp.getDefault().toString(); + } + } else if (p instanceof DoubleProperty) { + DoubleProperty dp = (DoubleProperty) p; + if (dp.getDefault() != null) { + return dp.getDefault().toString(); + } + } else if (p instanceof FloatProperty) { + FloatProperty dp = (FloatProperty) p; + if (dp.getDefault() != null) { + return dp.getDefault().toString(); + } + } else if (p instanceof BooleanProperty) { + BooleanProperty bp = (BooleanProperty) p; + if (bp.getDefault() != null) { + return bp.getDefault().toString(); + } + } else if (p instanceof StringProperty) { + StringProperty sp = (StringProperty) p; + if (sp.getDefault() != null) { + return "\"" + escapeText(sp.getDefault()) + "\""; + } + } + + return null; + } + @Override public String getSwaggerType(Property p) { String swaggerType = super.getSwaggerType(p); @@ -204,10 +239,6 @@ public class RubyClientCodegen extends DefaultCodegen implements CodegenConfig { return type; } - public String toDefaultValue(Property p) { - return "null"; - } - @Override public String toVarName(String name) { // sanitize name diff --git a/modules/swagger-codegen/src/main/resources/ruby/model.mustache b/modules/swagger-codegen/src/main/resources/ruby/model.mustache index 35742384c260..aff5ba60c02c 100644 --- a/modules/swagger-codegen/src/main/resources/ruby/model.mustache +++ b/modules/swagger-codegen/src/main/resources/ruby/model.mustache @@ -21,7 +21,7 @@ module {{moduleName}} end def initialize(attributes = {}) - return if !attributes.is_a?(Hash) || attributes.empty? + return unless attributes.is_a?(Hash) # convert string to symbol for hash key attributes = attributes.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo} @@ -30,7 +30,9 @@ module {{moduleName}} if attributes[:'{{{baseName}}}'] {{#isContainer}}if (value = attributes[:'{{{baseName}}}']).is_a?(Array) self.{{{name}}} = value - end{{/isContainer}}{{^isContainer}}self.{{{name}}} = attributes[:'{{{baseName}}}']{{/isContainer}} + end{{/isContainer}}{{^isContainer}}self.{{{name}}} = attributes[:'{{{baseName}}}']{{/isContainer}}{{#defaultValue}} + else + self.{{{name}}} = {{{defaultValue}}}{{/defaultValue}} end {{/vars}} end diff --git a/samples/client/petstore/ruby/lib/petstore/models/category.rb b/samples/client/petstore/ruby/lib/petstore/models/category.rb index ab5b9cabbaaa..8a0db2486569 100644 --- a/samples/client/petstore/ruby/lib/petstore/models/category.rb +++ b/samples/client/petstore/ruby/lib/petstore/models/category.rb @@ -25,7 +25,7 @@ module Petstore end def initialize(attributes = {}) - return if !attributes.is_a?(Hash) || attributes.empty? + return unless attributes.is_a?(Hash) # convert string to symbol for hash key attributes = attributes.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo} diff --git a/samples/client/petstore/ruby/lib/petstore/models/order.rb b/samples/client/petstore/ruby/lib/petstore/models/order.rb index 74eab3436e3e..c8de9162980f 100644 --- a/samples/client/petstore/ruby/lib/petstore/models/order.rb +++ b/samples/client/petstore/ruby/lib/petstore/models/order.rb @@ -41,7 +41,7 @@ module Petstore end def initialize(attributes = {}) - return if !attributes.is_a?(Hash) || attributes.empty? + return unless attributes.is_a?(Hash) # convert string to symbol for hash key attributes = attributes.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo} diff --git a/samples/client/petstore/ruby/lib/petstore/models/pet.rb b/samples/client/petstore/ruby/lib/petstore/models/pet.rb index 8c5fe6e17e7f..dcfe46d95348 100644 --- a/samples/client/petstore/ruby/lib/petstore/models/pet.rb +++ b/samples/client/petstore/ruby/lib/petstore/models/pet.rb @@ -41,7 +41,7 @@ module Petstore end def initialize(attributes = {}) - return if !attributes.is_a?(Hash) || attributes.empty? + return unless attributes.is_a?(Hash) # convert string to symbol for hash key attributes = attributes.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo} diff --git a/samples/client/petstore/ruby/lib/petstore/models/tag.rb b/samples/client/petstore/ruby/lib/petstore/models/tag.rb index 51439de58466..0861036ef184 100644 --- a/samples/client/petstore/ruby/lib/petstore/models/tag.rb +++ b/samples/client/petstore/ruby/lib/petstore/models/tag.rb @@ -25,7 +25,7 @@ module Petstore end def initialize(attributes = {}) - return if !attributes.is_a?(Hash) || attributes.empty? + return unless attributes.is_a?(Hash) # convert string to symbol for hash key attributes = attributes.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo} diff --git a/samples/client/petstore/ruby/lib/petstore/models/user.rb b/samples/client/petstore/ruby/lib/petstore/models/user.rb index 3d20ab95c4f4..01bcc8223477 100644 --- a/samples/client/petstore/ruby/lib/petstore/models/user.rb +++ b/samples/client/petstore/ruby/lib/petstore/models/user.rb @@ -49,7 +49,7 @@ module Petstore end def initialize(attributes = {}) - return if !attributes.is_a?(Hash) || attributes.empty? + return unless attributes.is_a?(Hash) # convert string to symbol for hash key attributes = attributes.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo} From b896c9169a48f4df946ef8ae425a62ac354b3eb6 Mon Sep 17 00:00:00 2001 From: xhh Date: Wed, 9 Dec 2015 11:16:14 +0800 Subject: [PATCH 22/71] Add comments to model classes in Ruby client --- .../src/main/resources/ruby/model.mustache | 19 ++++++++++++------- .../ruby/lib/petstore/models/category.rb | 11 ++++++----- .../ruby/lib/petstore/models/order.rb | 15 +++++++-------- .../petstore/ruby/lib/petstore/models/pet.rb | 15 +++++++-------- .../petstore/ruby/lib/petstore/models/tag.rb | 11 ++++++----- .../petstore/ruby/lib/petstore/models/user.rb | 16 ++++++---------- 6 files changed, 44 insertions(+), 43 deletions(-) diff --git a/modules/swagger-codegen/src/main/resources/ruby/model.mustache b/modules/swagger-codegen/src/main/resources/ruby/model.mustache index aff5ba60c02c..5d4eb954767a 100644 --- a/modules/swagger-codegen/src/main/resources/ruby/model.mustache +++ b/modules/swagger-codegen/src/main/resources/ruby/model.mustache @@ -1,18 +1,19 @@ -module {{moduleName}} -{{#models}} # {{description}} -{{#model}} class {{classname}} < BaseObject +module {{moduleName}}{{#models}}{{#model}}{{#description}} + # {{{description}}}{{/description}} + class {{classname}} < BaseObject attr_accessor {{#vars}}:{{{name}}}{{#hasMore}}, {{/hasMore}}{{/vars}}{{newline}} - # attribute mapping from ruby-style variable name to JSON key + + # Attribute mapping from ruby-style variable name to JSON key. def self.attribute_map { - {{#vars}} - # {{description}} + {{#vars}}{{#description}} + # {{{description}}}{{/description}} :'{{{name}}}' => :'{{{baseName}}}'{{#hasMore}},{{/hasMore}} {{/vars}} } end - # attribute type + # Attribute type mapping. def self.swagger_types { {{#vars}}:'{{{name}}}' => :'{{{datatype}}}'{{#hasMore}},{{/hasMore}} @@ -37,6 +38,7 @@ module {{moduleName}} {{/vars}} end {{#vars}}{{#isEnum}} + # Custom attribute writer method checking allowed values (enum). def {{{name}}}=({{{name}}}) allowed_values = [{{#allowableValues}}{{#values}}"{{{this}}}"{{^-last}}, {{/-last}}{{/values}}{{/allowableValues}}] if {{{name}}} && !allowed_values.include?({{{name}}}) @@ -45,16 +47,19 @@ module {{moduleName}} @{{{name}}} = {{{name}}} end {{/isEnum}}{{/vars}} + # Check equality by comparing each attribute. def ==(o) return true if self.equal?(o) self.class == o.class{{#vars}} && {{name}} == o.{{name}}{{/vars}} end + # @see the `==` method def eql?(o) self == o end + # Calculate hash code according to all attributes. def hash [{{#vars}}{{name}}{{#hasMore}}, {{/hasMore}}{{/vars}}].hash end diff --git a/samples/client/petstore/ruby/lib/petstore/models/category.rb b/samples/client/petstore/ruby/lib/petstore/models/category.rb index 8a0db2486569..8864ad10f753 100644 --- a/samples/client/petstore/ruby/lib/petstore/models/category.rb +++ b/samples/client/petstore/ruby/lib/petstore/models/category.rb @@ -1,21 +1,19 @@ module Petstore - # class Category < BaseObject attr_accessor :id, :name - # attribute mapping from ruby-style variable name to JSON key + + # Attribute mapping from ruby-style variable name to JSON key. def self.attribute_map { - # :'id' => :'id', - # :'name' => :'name' } end - # attribute type + # Attribute type mapping. def self.swagger_types { :'id' => :'Integer', @@ -41,6 +39,7 @@ module Petstore end + # Check equality by comparing each attribute. def ==(o) return true if self.equal?(o) self.class == o.class && @@ -48,10 +47,12 @@ module Petstore name == o.name end + # @see the `==` method def eql?(o) self == o end + # Calculate hash code according to all attributes. def hash [id, name].hash end diff --git a/samples/client/petstore/ruby/lib/petstore/models/order.rb b/samples/client/petstore/ruby/lib/petstore/models/order.rb index c8de9162980f..59c84f656660 100644 --- a/samples/client/petstore/ruby/lib/petstore/models/order.rb +++ b/samples/client/petstore/ruby/lib/petstore/models/order.rb @@ -1,33 +1,28 @@ module Petstore - # class Order < BaseObject attr_accessor :id, :pet_id, :quantity, :ship_date, :status, :complete - # attribute mapping from ruby-style variable name to JSON key + + # Attribute mapping from ruby-style variable name to JSON key. def self.attribute_map { - # :'id' => :'id', - # :'pet_id' => :'petId', - # :'quantity' => :'quantity', - # :'ship_date' => :'shipDate', # Order Status :'status' => :'status', - # :'complete' => :'complete' } end - # attribute type + # Attribute type mapping. def self.swagger_types { :'id' => :'Integer', @@ -73,6 +68,7 @@ module Petstore end + # Custom attribute writer method checking allowed values (enum). def status=(status) allowed_values = ["placed", "approved", "delivered"] if status && !allowed_values.include?(status) @@ -81,6 +77,7 @@ module Petstore @status = status end + # Check equality by comparing each attribute. def ==(o) return true if self.equal?(o) self.class == o.class && @@ -92,10 +89,12 @@ module Petstore complete == o.complete end + # @see the `==` method def eql?(o) self == o end + # Calculate hash code according to all attributes. def hash [id, pet_id, quantity, ship_date, status, complete].hash end diff --git a/samples/client/petstore/ruby/lib/petstore/models/pet.rb b/samples/client/petstore/ruby/lib/petstore/models/pet.rb index dcfe46d95348..303a12d702cd 100644 --- a/samples/client/petstore/ruby/lib/petstore/models/pet.rb +++ b/samples/client/petstore/ruby/lib/petstore/models/pet.rb @@ -1,24 +1,19 @@ module Petstore - # class Pet < BaseObject attr_accessor :id, :category, :name, :photo_urls, :tags, :status - # attribute mapping from ruby-style variable name to JSON key + + # Attribute mapping from ruby-style variable name to JSON key. def self.attribute_map { - # :'id' => :'id', - # :'category' => :'category', - # :'name' => :'name', - # :'photo_urls' => :'photoUrls', - # :'tags' => :'tags', # pet status in the store @@ -27,7 +22,7 @@ module Petstore } end - # attribute type + # Attribute type mapping. def self.swagger_types { :'id' => :'Integer', @@ -77,6 +72,7 @@ module Petstore end + # Custom attribute writer method checking allowed values (enum). def status=(status) allowed_values = ["available", "pending", "sold"] if status && !allowed_values.include?(status) @@ -85,6 +81,7 @@ module Petstore @status = status end + # Check equality by comparing each attribute. def ==(o) return true if self.equal?(o) self.class == o.class && @@ -96,10 +93,12 @@ module Petstore status == o.status end + # @see the `==` method def eql?(o) self == o end + # Calculate hash code according to all attributes. def hash [id, category, name, photo_urls, tags, status].hash end diff --git a/samples/client/petstore/ruby/lib/petstore/models/tag.rb b/samples/client/petstore/ruby/lib/petstore/models/tag.rb index 0861036ef184..06d779c2c547 100644 --- a/samples/client/petstore/ruby/lib/petstore/models/tag.rb +++ b/samples/client/petstore/ruby/lib/petstore/models/tag.rb @@ -1,21 +1,19 @@ module Petstore - # class Tag < BaseObject attr_accessor :id, :name - # attribute mapping from ruby-style variable name to JSON key + + # Attribute mapping from ruby-style variable name to JSON key. def self.attribute_map { - # :'id' => :'id', - # :'name' => :'name' } end - # attribute type + # Attribute type mapping. def self.swagger_types { :'id' => :'Integer', @@ -41,6 +39,7 @@ module Petstore end + # Check equality by comparing each attribute. def ==(o) return true if self.equal?(o) self.class == o.class && @@ -48,10 +47,12 @@ module Petstore name == o.name end + # @see the `==` method def eql?(o) self == o end + # Calculate hash code according to all attributes. def hash [id, name].hash end diff --git a/samples/client/petstore/ruby/lib/petstore/models/user.rb b/samples/client/petstore/ruby/lib/petstore/models/user.rb index 01bcc8223477..1b49db1c96be 100644 --- a/samples/client/petstore/ruby/lib/petstore/models/user.rb +++ b/samples/client/petstore/ruby/lib/petstore/models/user.rb @@ -1,30 +1,23 @@ module Petstore - # class User < BaseObject attr_accessor :id, :username, :first_name, :last_name, :email, :password, :phone, :user_status - # attribute mapping from ruby-style variable name to JSON key + + # Attribute mapping from ruby-style variable name to JSON key. def self.attribute_map { - # :'id' => :'id', - # :'username' => :'username', - # :'first_name' => :'firstName', - # :'last_name' => :'lastName', - # :'email' => :'email', - # :'password' => :'password', - # :'phone' => :'phone', # User Status @@ -33,7 +26,7 @@ module Petstore } end - # attribute type + # Attribute type mapping. def self.swagger_types { :'id' => :'Integer', @@ -89,6 +82,7 @@ module Petstore end + # Check equality by comparing each attribute. def ==(o) return true if self.equal?(o) self.class == o.class && @@ -102,10 +96,12 @@ module Petstore user_status == o.user_status end + # @see the `==` method def eql?(o) self == o end + # Calculate hash code according to all attributes. def hash [id, username, first_name, last_name, email, password, phone, user_status].hash end From 4fdaeb737127c46937c54c6e384c64c4762ec13b Mon Sep 17 00:00:00 2001 From: xhh Date: Wed, 9 Dec 2015 12:38:38 +0800 Subject: [PATCH 23/71] Improve checking of JSON MIME --- .../main/resources/ruby/api_client.mustache | 36 +++++++------- .../petstore/ruby/lib/petstore/api_client.rb | 36 +++++++------- .../petstore/ruby/spec/api_client_spec.rb | 47 +++++++++++++++++++ 3 files changed, 85 insertions(+), 34 deletions(-) diff --git a/modules/swagger-codegen/src/main/resources/ruby/api_client.mustache b/modules/swagger-codegen/src/main/resources/ruby/api_client.mustache index 3873d4765777..fa14e2f88ca4 100644 --- a/modules/swagger-codegen/src/main/resources/ruby/api_client.mustache +++ b/modules/swagger-codegen/src/main/resources/ruby/api_client.mustache @@ -86,6 +86,15 @@ module {{moduleName}} Typhoeus::Request.new(url, req_opts) end + # Check if the given MIME is a JSON MIME. + # JSON MIME examples: + # application/json + # application/json; charset=UTF8 + # APPLICATION/JSON + def json_mime?(mime) + !!(mime =~ /\Aapplication\/json(;.*)?\z/i) + end + # Deserialize the response to the given return type. # # @param [String] return_type some examples: "User", "Array[User]", "Hash[String,Integer]" @@ -99,9 +108,7 @@ module {{moduleName}} # ensuring a default content type content_type = response.headers['Content-Type'] || 'application/json' - unless content_type.start_with?('application/json') - fail "Content-Type is not supported: #{content_type}" - end + fail "Content-Type is not supported: #{content_type}" unless json_mime?(content_type) begin data = JSON.parse("[#{body}]", :symbolize_names => true)[0] @@ -228,26 +235,21 @@ module {{moduleName}} # @param [Array] accepts array for Accept # @return [String] the Accept header (e.g. application/json) def select_header_accept(accepts) - if accepts.empty? - return - elsif accepts.any?{ |s| s.casecmp('application/json') == 0 } - 'application/json' # look for json data by default - else - accepts.join(',') - end + return nil if accepts.nil? || accepts.empty? + # use JSON when present, otherwise use all of the provided + json_accept = accepts.find { |s| json_mime?(s) } + return json_accept || accepts.join(',') end # Return Content-Type header based on an array of content types provided. # @param [Array] content_types array for Content-Type # @return [String] the Content-Type header (e.g. application/json) def select_header_content_type(content_types) - if content_types.empty? - 'application/json' # use application/json by default - elsif content_types.any?{ |s| s.casecmp('application/json')==0 } - 'application/json' # use application/json if it's included - else - content_types[0] # otherwise, use the first one - end + # use application/json by default + return 'application/json' if content_types.nil? || content_types.empty? + # use JSON when present, otherwise use the first one + json_content_type = content_types.find { |s| json_mime?(s) } + return json_content_type || content_types.first end # Convert object (array, hash, object, etc) to JSON string. diff --git a/samples/client/petstore/ruby/lib/petstore/api_client.rb b/samples/client/petstore/ruby/lib/petstore/api_client.rb index 412fb7946ad4..0648ee54cf35 100644 --- a/samples/client/petstore/ruby/lib/petstore/api_client.rb +++ b/samples/client/petstore/ruby/lib/petstore/api_client.rb @@ -86,6 +86,15 @@ module Petstore Typhoeus::Request.new(url, req_opts) end + # Check if the given MIME is a JSON MIME. + # JSON MIME examples: + # application/json + # application/json; charset=UTF8 + # APPLICATION/JSON + def json_mime?(mime) + !!(mime =~ /\Aapplication\/json(;.*)?\z/i) + end + # Deserialize the response to the given return type. # # @param [String] return_type some examples: "User", "Array[User]", "Hash[String,Integer]" @@ -99,9 +108,7 @@ module Petstore # ensuring a default content type content_type = response.headers['Content-Type'] || 'application/json' - unless content_type.start_with?('application/json') - fail "Content-Type is not supported: #{content_type}" - end + fail "Content-Type is not supported: #{content_type}" unless json_mime?(content_type) begin data = JSON.parse("[#{body}]", :symbolize_names => true)[0] @@ -228,26 +235,21 @@ module Petstore # @param [Array] accepts array for Accept # @return [String] the Accept header (e.g. application/json) def select_header_accept(accepts) - if accepts.empty? - return - elsif accepts.any?{ |s| s.casecmp('application/json') == 0 } - 'application/json' # look for json data by default - else - accepts.join(',') - end + return nil if accepts.nil? || accepts.empty? + # use JSON when present, otherwise use all of the provided + json_accept = accepts.find { |s| json_mime?(s) } + return json_accept || accepts.join(',') end # Return Content-Type header based on an array of content types provided. # @param [Array] content_types array for Content-Type # @return [String] the Content-Type header (e.g. application/json) def select_header_content_type(content_types) - if content_types.empty? - 'application/json' # use application/json by default - elsif content_types.any?{ |s| s.casecmp('application/json')==0 } - 'application/json' # use application/json if it's included - else - content_types[0] # otherwise, use the first one - end + # use application/json by default + return 'application/json' if content_types.nil? || content_types.empty? + # use JSON when present, otherwise use the first one + json_content_type = content_types.find { |s| json_mime?(s) } + return json_content_type || content_types.first end # Convert object (array, hash, object, etc) to JSON string. diff --git a/samples/client/petstore/ruby/spec/api_client_spec.rb b/samples/client/petstore/ruby/spec/api_client_spec.rb index eeb27300bf37..054f63bc4ef8 100644 --- a/samples/client/petstore/ruby/spec/api_client_spec.rb +++ b/samples/client/petstore/ruby/spec/api_client_spec.rb @@ -145,4 +145,51 @@ describe Petstore::ApiClient do end end + describe "#json_mime?" do + let(:api_client) { Petstore::ApiClient.new } + + it "works" do + api_client.json_mime?(nil).should == false + api_client.json_mime?('').should == false + + api_client.json_mime?('application/json').should == true + api_client.json_mime?('application/json; charset=UTF8').should == true + api_client.json_mime?('APPLICATION/JSON').should == true + + api_client.json_mime?('application/xml').should == false + api_client.json_mime?('text/plain').should == false + end + end + + describe "#select_header_accept" do + let(:api_client) { Petstore::ApiClient.new } + + it "works" do + api_client.select_header_accept(nil).should == nil + api_client.select_header_accept([]).should == nil + + api_client.select_header_accept(['application/json']).should == 'application/json' + api_client.select_header_accept(['application/xml', 'application/json; charset=UTF8']).should == 'application/json; charset=UTF8' + api_client.select_header_accept(['APPLICATION/JSON', 'text/html']).should == 'APPLICATION/JSON' + + api_client.select_header_accept(['application/xml']).should == 'application/xml' + api_client.select_header_accept(['text/html', 'application/xml']).should == 'text/html,application/xml' + end + end + + describe "#select_header_content_type" do + let(:api_client) { Petstore::ApiClient.new } + + it "works" do + api_client.select_header_content_type(nil).should == 'application/json' + api_client.select_header_content_type([]).should == 'application/json' + + api_client.select_header_content_type(['application/json']).should == 'application/json' + api_client.select_header_content_type(['application/xml', 'application/json; charset=UTF8']).should == 'application/json; charset=UTF8' + api_client.select_header_content_type(['APPLICATION/JSON', 'text/html']).should == 'APPLICATION/JSON' + api_client.select_header_content_type(['application/xml']).should == 'application/xml' + api_client.select_header_content_type(['text/plain', 'application/xml']).should == 'text/plain' + end + end + end From bf3c1d36d5b579ad86654e2cf8172e858c583b49 Mon Sep 17 00:00:00 2001 From: wing328 Date: Wed, 9 Dec 2015 15:34:39 +0800 Subject: [PATCH 24/71] add default value to python model --- .../languages/PythonClientCodegen.java | 59 ++++++++++++++++--- .../src/main/resources/python/model.mustache | 2 +- samples/client/petstore/python/.coverage | 2 +- .../petstore/python/dev-requirements.txt.log | 56 ++++++++++++++++++ 4 files changed, 110 insertions(+), 9 deletions(-) diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/PythonClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/PythonClientCodegen.java index 1759e5152581..b5aa56aa2c46 100755 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/PythonClientCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/PythonClientCodegen.java @@ -6,9 +6,7 @@ import io.swagger.codegen.CodegenConstants; import io.swagger.codegen.CodegenType; import io.swagger.codegen.DefaultCodegen; import io.swagger.codegen.SupportingFile; -import io.swagger.models.properties.ArrayProperty; -import io.swagger.models.properties.MapProperty; -import io.swagger.models.properties.Property; +import io.swagger.models.properties.*; import java.io.File; import java.util.Arrays; @@ -166,10 +164,6 @@ public class PythonClientCodegen extends DefaultCodegen implements CodegenConfig return type; } - public String toDefaultValue(Property p) { - return "None"; - } - @Override public String toVarName(String name) { // sanitize name @@ -291,4 +285,55 @@ public class PythonClientCodegen extends DefaultCodegen implements CodegenConfig public String generatePackageName(String packageName) { return underscore(packageName.replaceAll("[^\\w]+", "")); } + + /** + * Return the default value of the property + * + * @param p Swagger property object + * @return string presentation of the default value of the property + */ + @Override + public String toDefaultValue(Property p) { + if (p instanceof StringProperty) { + StringProperty dp = (StringProperty) p; + if (dp.getDefault() != null) { + return "'" + dp.getDefault().toString() + "'"; + } + } else if (p instanceof BooleanProperty) { + BooleanProperty dp = (BooleanProperty) p; + if (dp.getDefault() != null) { + if (dp.getDefault().toString().equalsIgnoreCase("false")) + return "False"; + else + return "True"; + } + } else if (p instanceof DateProperty) { + // TODO + } else if (p instanceof DateTimeProperty) { + // TODO + } else if (p instanceof DoubleProperty) { + DoubleProperty dp = (DoubleProperty) p; + if (dp.getDefault() != null) { + return dp.getDefault().toString(); + } + } else if (p instanceof FloatProperty) { + FloatProperty dp = (FloatProperty) p; + if (dp.getDefault() != null) { + return dp.getDefault().toString(); + } + } else if (p instanceof IntegerProperty) { + IntegerProperty dp = (IntegerProperty) p; + if (dp.getDefault() != null) { + return dp.getDefault().toString(); + } + } else if (p instanceof LongProperty) { + LongProperty dp = (LongProperty) p; + if (dp.getDefault() != null) { + return dp.getDefault().toString(); + } + } + + return null; + } + } diff --git a/modules/swagger-codegen/src/main/resources/python/model.mustache b/modules/swagger-codegen/src/main/resources/python/model.mustache index 0dbe29add4fc..aae43175a2ed 100644 --- a/modules/swagger-codegen/src/main/resources/python/model.mustache +++ b/modules/swagger-codegen/src/main/resources/python/model.mustache @@ -49,7 +49,7 @@ class {{classname}}(object): } {{#vars}} - self._{{name}} = None + self._{{name}} = {{#defaultValue}}{{{defaultValue}}}{{/defaultValue}}{{^defaultValue}}None{{/defaultValue}} {{/vars}} {{#vars}} diff --git a/samples/client/petstore/python/.coverage b/samples/client/petstore/python/.coverage index 98dd5627b871..26331c636b39 100644 --- a/samples/client/petstore/python/.coverage +++ b/samples/client/petstore/python/.coverage @@ -1 +1 @@ -!coverage.py: This is a private format, don't read it directly!{"lines": {"/Users/williamcheng/Code/wing328/swagger-codegen/samples/client/petstore/python/swagger_client/models/order.py": [130, 172, 141, 173, 19, 21, 22, 152, 25, 29, 30, 161, 163, 39, 40, 41, 42, 43, 44, 45, 174, 175, 48, 49, 50, 51, 180, 53, 54, 52, 58, 59, 60, 61, 62, 191, 64, 202, 75, 86, 57, 176, 222, 97, 228, 178, 234, 108, 240, 119], "/Users/williamcheng/Code/wing328/swagger-codegen/samples/client/petstore/python/swagger_client/models/tag.py": [128, 132, 134, 19, 21, 22, 25, 29, 30, 39, 40, 41, 44, 45, 46, 49, 50, 52, 61, 63, 72, 74, 83, 85, 94, 96, 100, 102, 103, 104, 109, 112, 114, 116, 122], "/Users/williamcheng/Code/wing328/swagger-codegen/samples/client/petstore/python/swagger_client/models/__init__.py": [1, 4, 5, 6, 7, 8], "/Users/williamcheng/Code/wing328/swagger-codegen/samples/client/petstore/python/swagger_client/apis/__init__.py": [1, 4, 5, 6], "/Users/williamcheng/Code/wing328/swagger-codegen/samples/client/petstore/python/swagger_client/models/pet.py": [128, 130, 150, 172, 139, 141, 19, 215, 21, 22, 152, 25, 29, 30, 161, 163, 39, 40, 41, 42, 43, 44, 45, 174, 48, 49, 50, 51, 52, 53, 54, 183, 185, 58, 59, 60, 61, 62, 64, 194, 195, 200, 73, 202, 75, 206, 208, 209, 210, 211, 84, 213, 86, 57, 216, 218, 220, 222, 95, 97, 226, 228, 234, 108, 238, 240, 117, 119, 212, 106], "/Users/williamcheng/Code/wing328/swagger-codegen/samples/client/petstore/python/swagger_client/configuration.py": [135, 136, 137, 138, 139, 142, 19, 149, 22, 23, 25, 26, 157, 158, 31, 32, 34, 36, 37, 39, 40, 41, 170, 43, 172, 46, 47, 189, 179, 52, 54, 59, 61, 190, 63, 192, 224, 67, 69, 71, 200, 73, 204, 80, 81, 82, 84, 213, 86, 199, 88, 90, 219, 92, 221, 222, 223, 96, 225, 98, 100, 102, 230, 104, 167, 111, 76, 168, 122, 123, 42, 21], "/Users/williamcheng/Code/wing328/swagger-codegen/samples/client/petstore/python/swagger_client/apis/store_api.py": [87, 18, 276, 22, 23, 26, 28, 29, 197, 32, 37, 39, 40, 41, 44, 46, 48, 68, 69, 71, 72, 79, 82, 83, 85, 121, 89, 91, 92, 94, 97, 98, 99, 103, 104, 107, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 20], "/Users/williamcheng/Code/wing328/swagger-codegen/samples/client/petstore/python/swagger_client/models/category.py": [128, 134, 19, 21, 22, 25, 29, 30, 39, 40, 41, 44, 45, 46, 49, 50, 52, 61, 63, 72, 74, 83, 85, 94, 96, 100, 102, 103, 104, 109, 112, 114, 116, 122], "/Users/williamcheng/Code/wing328/swagger-codegen/samples/client/petstore/python/swagger_client/api_client.py": [518, 525, 526, 527, 19, 21, 22, 23, 24, 537, 26, 27, 28, 29, 30, 31, 32, 33, 34, 547, 36, 37, 40, 42, 44, 45, 558, 47, 49, 52, 566, 568, 569, 570, 571, 572, 573, 575, 68, 69, 70, 75, 76, 77, 79, 80, 82, 84, 91, 96, 98, 102, 103, 104, 107, 108, 109, 111, 112, 115, 116, 117, 118, 119, 120, 123, 124, 125, 126, 129, 130, 131, 134, 137, 138, 141, 144, 145, 146, 147, 149, 152, 153, 155, 157, 158, 160, 162, 171, 172, 174, 176, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 204, 205, 212, 213, 214, 216, 217, 219, 231, 235, 236, 240, 242, 251, 252, 254, 255, 256, 257, 258, 260, 261, 262, 263, 267, 268, 269, 272, 274, 275, 276, 278, 279, 280, 281, 283, 286, 287, 288, 316, 317, 318, 319, 320, 322, 323, 324, 325, 326, 327, 328, 329, 330, 332, 333, 337, 338, 339, 340, 341, 345, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 369, 370, 371, 372, 379, 387, 389, 390, 392, 393, 394, 395, 548, 397, 398, 399, 400, 401, 402, 404, 406, 413, 414, 416, 418, 419, 421, 423, 430, 431, 433, 435, 436, 438, 440, 448, 450, 453, 454, 455, 456, 458, 459, 467, 546, 493, 502, 503, 508, 510], "/Users/williamcheng/Code/wing328/swagger-codegen/samples/client/petstore/python/swagger_client/apis/pet_api.py": [512, 513, 514, 516, 86, 18, 20, 22, 23, 26, 539, 28, 29, 542, 543, 32, 548, 37, 39, 40, 41, 42, 555, 556, 45, 558, 559, 48, 562, 564, 565, 566, 568, 569, 345, 571, 574, 575, 576, 580, 581, 70, 584, 73, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 598, 88, 90, 92, 93, 95, 96, 97, 100, 101, 102, 106, 107, 621, 622, 624, 625, 626, 79, 116, 117, 118, 631, 632, 121, 122, 635, 124, 638, 639, 641, 642, 643, 645, 647, 649, 650, 651, 652, 653, 654, 656, 145, 146, 659, 660, 149, 150, 665, 666, 155, 156, 669, 671, 160, 673, 162, 675, 164, 677, 166, 679, 168, 169, 171, 172, 173, 541, 176, 177, 178, 115, 182, 183, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 200, 119, 120, 377, 221, 222, 549, 224, 225, 226, 231, 232, 235, 236, 110, 238, 240, 552, 242, 244, 246, 247, 249, 383, 252, 253, 254, 258, 259, 262, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 276, 46, 560, 538, 297, 298, 300, 301, 302, 44, 307, 308, 311, 312, 314, 316, 317, 318, 320, 322, 323, 325, 113, 328, 329, 330, 334, 335, 338, 340, 341, 342, 343, 344, 241, 346, 347, 348, 349, 350, 485, 352, 84, 114, 373, 374, 376, 148, 378, 661, 384, 387, 390, 391, 393, 394, 395, 397, 399, 401, 402, 404, 407, 408, 409, 413, 414, 69, 417, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 431, 72, 159, 74, 672, 83, 454, 455, 457, 458, 459, 674, 112, 464, 465, 468, 471, 472, 676, 474, 475, 476, 478, 480, 80, 482, 483, 484, 678, 486, 487, 489, 492, 493, 494, 680, 498, 499, 502, 681, 504, 505, 506, 507, 508, 509, 510, 511], "/Users/williamcheng/Code/wing328/swagger-codegen/samples/client/petstore/python/swagger_client/apis/user_api.py": [32, 355, 37, 39, 200, 124, 428, 589, 48, 18, 20, 22, 23, 276, 26, 507, 28, 29], "/Users/williamcheng/Code/wing328/swagger-codegen/samples/client/petstore/python/swagger_client/models/user.py": [278, 136, 266, 272, 147, 21, 22, 25, 284, 29, 158, 169, 180, 30, 191, 70, 202, 81, 213, 92, 224, 103, 235, 114, 19, 246, 125], "/Users/williamcheng/Code/wing328/swagger-codegen/samples/client/petstore/python/swagger_client/__init__.py": [1, 4, 5, 6, 7, 8, 11, 12, 13, 16, 18, 20], "/Users/williamcheng/Code/wing328/swagger-codegen/samples/client/petstore/python/swagger_client/rest.py": [20, 21, 23, 24, 25, 26, 27, 28, 31, 33, 35, 36, 40, 42, 43, 45, 48, 51, 53, 54, 55, 56, 57, 59, 63, 65, 72, 74, 82, 83, 88, 92, 95, 98, 101, 102, 103, 104, 105, 106, 109, 110, 121, 122, 124, 129, 130, 132, 135, 137, 138, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 152, 153, 154, 155, 156, 159, 160, 161, 166, 170, 174, 176, 177, 179, 181, 182, 183, 184, 186, 191, 198, 199, 200, 201, 203, 204, 205, 206, 207, 208, 210, 211, 212, 213, 214, 215, 217, 225, 227, 228, 229, 230, 231, 232, 239, 243, 244, 245, 246, 248, 249, 251]}} \ No newline at end of file +!coverage.py: This is a private format, don't read it directly!{"lines": {"/Users/williamcheng/Code/wing328/swagger-codegen/samples/client/petstore/python/swagger_client/__init__.py": [1, 4, 5, 6, 7, 8, 11, 12, 13, 16, 18, 20], "/Users/williamcheng/Code/wing328/swagger-codegen/samples/client/petstore/python/swagger_client/apis/pet_api.py": [512, 513, 514, 516, 86, 18, 20, 22, 23, 26, 539, 28, 29, 542, 543, 32, 548, 37, 39, 40, 41, 42, 555, 556, 45, 558, 559, 560, 562, 564, 565, 566, 568, 569, 571, 574, 575, 576, 580, 581, 70, 584, 73, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 598, 88, 90, 92, 93, 95, 96, 97, 100, 101, 102, 106, 107, 621, 622, 624, 625, 626, 79, 116, 117, 118, 631, 632, 121, 122, 635, 124, 638, 639, 641, 642, 643, 645, 647, 649, 650, 651, 652, 653, 654, 656, 145, 146, 659, 148, 661, 150, 665, 666, 155, 156, 538, 159, 160, 673, 162, 675, 164, 677, 166, 679, 168, 169, 171, 172, 173, 541, 176, 177, 178, 115, 182, 183, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 200, 119, 120, 377, 221, 222, 549, 224, 225, 226, 231, 232, 431, 235, 236, 110, 238, 240, 552, 242, 244, 246, 247, 249, 383, 252, 253, 254, 258, 259, 262, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 276, 46, 48, 297, 298, 300, 301, 302, 44, 307, 308, 311, 312, 314, 316, 317, 318, 320, 322, 323, 325, 113, 328, 329, 330, 334, 335, 338, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 485, 352, 84, 114, 373, 374, 376, 660, 378, 149, 384, 387, 390, 391, 393, 394, 395, 397, 399, 401, 402, 404, 407, 408, 409, 413, 414, 69, 417, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 669, 72, 241, 671, 74, 672, 83, 454, 455, 457, 458, 459, 674, 112, 464, 465, 468, 471, 472, 676, 474, 475, 476, 478, 480, 80, 482, 483, 484, 678, 486, 487, 489, 492, 493, 494, 680, 498, 499, 502, 681, 504, 505, 506, 507, 508, 509, 510, 511], "/Users/williamcheng/Code/wing328/swagger-codegen/samples/client/petstore/python/swagger_client/models/order.py": [130, 172, 141, 173, 19, 21, 22, 152, 25, 29, 30, 52, 161, 163, 39, 40, 41, 42, 43, 44, 45, 174, 175, 48, 49, 50, 51, 180, 53, 54, 57, 58, 59, 60, 61, 62, 191, 64, 202, 75, 86, 176, 222, 97, 228, 178, 234, 108, 240, 119], "/Users/williamcheng/Code/wing328/swagger-codegen/samples/client/petstore/python/swagger_client/models/__init__.py": [1, 4, 5, 6, 7, 8], "/Users/williamcheng/Code/wing328/swagger-codegen/samples/client/petstore/python/swagger_client/models/tag.py": [128, 132, 134, 72, 74, 109, 19, 21, 22, 104, 25, 29, 30, 96, 100, 114, 102, 39, 40, 41, 103, 44, 45, 46, 112, 49, 50, 83, 116, 94, 52, 122, 61, 85, 63], "/Users/williamcheng/Code/wing328/swagger-codegen/samples/client/petstore/python/swagger_client/apis/user_api.py": [32, 355, 37, 39, 200, 124, 428, 589, 48, 18, 20, 22, 23, 276, 26, 507, 28, 29], "/Users/williamcheng/Code/wing328/swagger-codegen/samples/client/petstore/python/swagger_client/configuration.py": [135, 136, 137, 138, 139, 142, 19, 149, 22, 23, 25, 26, 27, 29, 158, 31, 32, 34, 36, 37, 39, 40, 41, 170, 43, 172, 46, 47, 189, 179, 52, 54, 59, 61, 190, 63, 192, 224, 67, 69, 71, 200, 73, 204, 80, 81, 82, 84, 213, 86, 199, 88, 90, 219, 92, 221, 222, 223, 96, 225, 98, 100, 102, 230, 104, 167, 111, 76, 168, 157, 122, 123, 42, 21], "/Users/williamcheng/Code/wing328/swagger-codegen/samples/client/petstore/python/swagger_client/apis/store_api.py": [18, 276, 22, 23, 26, 28, 29, 197, 32, 37, 39, 40, 41, 44, 46, 48, 20, 68, 69, 71, 72, 79, 82, 83, 85, 87, 89, 91, 92, 94, 97, 98, 99, 103, 104, 107, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 121], "/Users/williamcheng/Code/wing328/swagger-codegen/samples/client/petstore/python/swagger_client/models/category.py": [128, 134, 72, 74, 109, 19, 21, 22, 104, 25, 29, 30, 96, 100, 114, 102, 39, 40, 41, 103, 44, 45, 46, 112, 49, 50, 83, 116, 94, 52, 122, 61, 85, 63], "/Users/williamcheng/Code/wing328/swagger-codegen/samples/client/petstore/python/swagger_client/rest.py": [20, 21, 23, 24, 25, 26, 27, 28, 31, 33, 35, 36, 40, 42, 48, 51, 53, 54, 55, 56, 57, 59, 63, 65, 72, 74, 82, 83, 88, 92, 95, 98, 101, 102, 103, 104, 105, 106, 109, 110, 121, 122, 124, 129, 130, 132, 135, 137, 138, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 152, 153, 154, 155, 156, 159, 160, 161, 166, 170, 171, 174, 176, 177, 179, 181, 182, 183, 184, 186, 191, 198, 199, 200, 201, 203, 204, 205, 206, 207, 208, 210, 211, 212, 213, 214, 215, 217, 225, 227, 228, 229, 230, 231, 232, 239, 243, 244, 245, 246, 248, 249, 251], "/Users/williamcheng/Code/wing328/swagger-codegen/samples/client/petstore/python/swagger_client/models/pet.py": [128, 130, 150, 172, 139, 141, 19, 215, 21, 22, 152, 25, 29, 30, 161, 163, 39, 40, 41, 42, 43, 44, 45, 174, 48, 49, 50, 51, 52, 53, 54, 183, 57, 58, 59, 60, 61, 62, 64, 194, 195, 200, 73, 202, 75, 206, 208, 209, 210, 211, 84, 213, 86, 185, 216, 218, 220, 222, 95, 97, 226, 228, 234, 108, 238, 240, 117, 119, 212, 106], "/Users/williamcheng/Code/wing328/swagger-codegen/samples/client/petstore/python/swagger_client/api_client.py": [518, 525, 526, 527, 19, 21, 22, 23, 24, 537, 26, 27, 28, 29, 30, 31, 32, 33, 34, 547, 36, 37, 40, 42, 44, 558, 49, 52, 566, 568, 569, 570, 571, 572, 573, 575, 68, 69, 70, 75, 76, 77, 79, 80, 82, 84, 91, 96, 98, 102, 103, 104, 107, 108, 109, 111, 112, 115, 116, 117, 118, 119, 120, 123, 124, 125, 126, 129, 130, 131, 134, 137, 138, 141, 144, 145, 146, 147, 149, 152, 153, 155, 157, 158, 160, 162, 171, 172, 174, 176, 191, 192, 194, 195, 196, 197, 198, 199, 200, 201, 202, 204, 205, 212, 213, 214, 216, 217, 219, 231, 235, 236, 240, 242, 251, 252, 254, 255, 256, 257, 258, 260, 261, 262, 263, 267, 268, 269, 272, 274, 275, 276, 278, 279, 280, 281, 283, 286, 287, 288, 316, 317, 318, 319, 320, 322, 323, 324, 325, 326, 327, 328, 329, 330, 332, 333, 337, 338, 339, 340, 341, 345, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 369, 370, 371, 372, 379, 387, 389, 390, 392, 393, 394, 395, 548, 397, 398, 399, 400, 401, 402, 404, 406, 413, 414, 416, 418, 419, 421, 423, 430, 431, 433, 435, 436, 438, 440, 448, 450, 453, 454, 455, 456, 458, 459, 467, 546, 493, 502, 503, 508, 510], "/Users/williamcheng/Code/wing328/swagger-codegen/samples/client/petstore/python/swagger_client/models/user.py": [278, 70, 136, 202, 272, 81, 147, 213, 22, 25, 92, 29, 158, 224, 103, 169, 235, 284, 114, 19, 180, 30, 246, 266, 191, 125, 21], "/Users/williamcheng/Code/wing328/swagger-codegen/samples/client/petstore/python/swagger_client/apis/__init__.py": [1, 4, 5, 6]}} \ No newline at end of file diff --git a/samples/client/petstore/python/dev-requirements.txt.log b/samples/client/petstore/python/dev-requirements.txt.log index 382d1cf081d6..bd935e805bfb 100644 --- a/samples/client/petstore/python/dev-requirements.txt.log +++ b/samples/client/petstore/python/dev-requirements.txt.log @@ -69,3 +69,59 @@ Requirement already satisfied (use --upgrade to upgrade): randomize in ./venv/li Requirement already satisfied (use --upgrade to upgrade): virtualenv>=1.11.2 in ./venv/lib/python2.7/site-packages (from tox->-r dev-requirements.txt (line 2)) Requirement already satisfied (use --upgrade to upgrade): py>=1.4.17 in ./venv/lib/python2.7/site-packages (from tox->-r dev-requirements.txt (line 2)) Requirement already satisfied (use --upgrade to upgrade): pluggy<0.4.0,>=0.3.0 in ./venv/lib/python2.7/site-packages (from tox->-r dev-requirements.txt (line 2)) +Collecting nose (from -r dev-requirements.txt (line 1)) + Using cached nose-1.3.7-py2-none-any.whl +Collecting tox (from -r dev-requirements.txt (line 2)) + Using cached tox-2.2.1-py2.py3-none-any.whl +Collecting coverage (from -r dev-requirements.txt (line 3)) + Downloading coverage-4.0.3.tar.gz (354kB) +Collecting randomize (from -r dev-requirements.txt (line 4)) + Using cached randomize-0.13-py2.py3-none-any.whl +Requirement already satisfied (use --upgrade to upgrade): virtualenv>=1.11.2 in /Library/Python/2.7/site-packages (from tox->-r dev-requirements.txt (line 2)) +Collecting py>=1.4.17 (from tox->-r dev-requirements.txt (line 2)) + Downloading py-1.4.31-py2.py3-none-any.whl (81kB) +Collecting pluggy<0.4.0,>=0.3.0 (from tox->-r dev-requirements.txt (line 2)) + Using cached pluggy-0.3.1-py2.py3-none-any.whl +Installing collected packages: nose, py, pluggy, tox, coverage, randomize +Collecting nose (from -r dev-requirements.txt (line 1)) + Using cached nose-1.3.7-py2-none-any.whl +Collecting tox (from -r dev-requirements.txt (line 2)) + Using cached tox-2.2.1-py2.py3-none-any.whl +Collecting coverage (from -r dev-requirements.txt (line 3)) + Using cached coverage-4.0.3.tar.gz +Collecting randomize (from -r dev-requirements.txt (line 4)) + Using cached randomize-0.13-py2.py3-none-any.whl +Requirement already satisfied (use --upgrade to upgrade): virtualenv>=1.11.2 in /Library/Python/2.7/site-packages (from tox->-r dev-requirements.txt (line 2)) +Collecting py>=1.4.17 (from tox->-r dev-requirements.txt (line 2)) + Using cached py-1.4.31-py2.py3-none-any.whl +Collecting pluggy<0.4.0,>=0.3.0 (from tox->-r dev-requirements.txt (line 2)) + Using cached pluggy-0.3.1-py2.py3-none-any.whl +Installing collected packages: nose, py, pluggy, tox, coverage, randomize +Requirement already satisfied (use --upgrade to upgrade): nose in ./venv/lib/python2.7/site-packages (from -r dev-requirements.txt (line 1)) +Requirement already satisfied (use --upgrade to upgrade): tox in ./venv/lib/python2.7/site-packages (from -r dev-requirements.txt (line 2)) +Requirement already satisfied (use --upgrade to upgrade): coverage in ./venv/lib/python2.7/site-packages (from -r dev-requirements.txt (line 3)) +Requirement already satisfied (use --upgrade to upgrade): randomize in ./venv/lib/python2.7/site-packages (from -r dev-requirements.txt (line 4)) +Requirement already satisfied (use --upgrade to upgrade): virtualenv>=1.11.2 in ./venv/lib/python2.7/site-packages (from tox->-r dev-requirements.txt (line 2)) +Requirement already satisfied (use --upgrade to upgrade): py>=1.4.17 in ./venv/lib/python2.7/site-packages (from tox->-r dev-requirements.txt (line 2)) +Requirement already satisfied (use --upgrade to upgrade): pluggy<0.4.0,>=0.3.0 in ./venv/lib/python2.7/site-packages (from tox->-r dev-requirements.txt (line 2)) +Requirement already satisfied (use --upgrade to upgrade): nose in ./venv/lib/python2.7/site-packages (from -r dev-requirements.txt (line 1)) +Requirement already satisfied (use --upgrade to upgrade): tox in ./venv/lib/python2.7/site-packages (from -r dev-requirements.txt (line 2)) +Requirement already satisfied (use --upgrade to upgrade): coverage in ./venv/lib/python2.7/site-packages (from -r dev-requirements.txt (line 3)) +Requirement already satisfied (use --upgrade to upgrade): randomize in ./venv/lib/python2.7/site-packages (from -r dev-requirements.txt (line 4)) +Requirement already satisfied (use --upgrade to upgrade): virtualenv>=1.11.2 in ./venv/lib/python2.7/site-packages (from tox->-r dev-requirements.txt (line 2)) +Requirement already satisfied (use --upgrade to upgrade): py>=1.4.17 in ./venv/lib/python2.7/site-packages (from tox->-r dev-requirements.txt (line 2)) +Requirement already satisfied (use --upgrade to upgrade): pluggy<0.4.0,>=0.3.0 in ./venv/lib/python2.7/site-packages (from tox->-r dev-requirements.txt (line 2)) +Requirement already satisfied (use --upgrade to upgrade): nose in ./venv/lib/python2.7/site-packages (from -r dev-requirements.txt (line 1)) +Requirement already satisfied (use --upgrade to upgrade): tox in ./venv/lib/python2.7/site-packages (from -r dev-requirements.txt (line 2)) +Requirement already satisfied (use --upgrade to upgrade): coverage in ./venv/lib/python2.7/site-packages (from -r dev-requirements.txt (line 3)) +Requirement already satisfied (use --upgrade to upgrade): randomize in ./venv/lib/python2.7/site-packages (from -r dev-requirements.txt (line 4)) +Requirement already satisfied (use --upgrade to upgrade): virtualenv>=1.11.2 in ./venv/lib/python2.7/site-packages (from tox->-r dev-requirements.txt (line 2)) +Requirement already satisfied (use --upgrade to upgrade): py>=1.4.17 in ./venv/lib/python2.7/site-packages (from tox->-r dev-requirements.txt (line 2)) +Requirement already satisfied (use --upgrade to upgrade): pluggy<0.4.0,>=0.3.0 in ./venv/lib/python2.7/site-packages (from tox->-r dev-requirements.txt (line 2)) +Requirement already satisfied (use --upgrade to upgrade): nose in ./venv/lib/python2.7/site-packages (from -r dev-requirements.txt (line 1)) +Requirement already satisfied (use --upgrade to upgrade): tox in ./venv/lib/python2.7/site-packages (from -r dev-requirements.txt (line 2)) +Requirement already satisfied (use --upgrade to upgrade): coverage in ./venv/lib/python2.7/site-packages (from -r dev-requirements.txt (line 3)) +Requirement already satisfied (use --upgrade to upgrade): randomize in ./venv/lib/python2.7/site-packages (from -r dev-requirements.txt (line 4)) +Requirement already satisfied (use --upgrade to upgrade): virtualenv>=1.11.2 in ./venv/lib/python2.7/site-packages (from tox->-r dev-requirements.txt (line 2)) +Requirement already satisfied (use --upgrade to upgrade): py>=1.4.17 in ./venv/lib/python2.7/site-packages (from tox->-r dev-requirements.txt (line 2)) +Requirement already satisfied (use --upgrade to upgrade): pluggy<0.4.0,>=0.3.0 in ./venv/lib/python2.7/site-packages (from tox->-r dev-requirements.txt (line 2)) From 921659be5cc565a01c0a2467ed7caa58ee9f0f9b Mon Sep 17 00:00:00 2001 From: xhh Date: Wed, 9 Dec 2015 16:09:15 +0800 Subject: [PATCH 25/71] Improve checking of JSON MIME in Java okhttp-gson client to support suffix like charset in "application/json; charset=UTF8" --- .../libraries/okhttp-gson/ApiClient.mustache | 39 +++++++++++++++---- .../java/io/swagger/client/ApiClient.java | 39 +++++++++++++++---- .../java/io/swagger/client/ApiClientTest.java | 33 +++++++++++----- 3 files changed, 87 insertions(+), 24 deletions(-) diff --git a/modules/swagger-codegen/src/main/resources/Java/libraries/okhttp-gson/ApiClient.mustache b/modules/swagger-codegen/src/main/resources/Java/libraries/okhttp-gson/ApiClient.mustache index e97e4c7f97d8..99dcdb517805 100644 --- a/modules/swagger-codegen/src/main/resources/Java/libraries/okhttp-gson/ApiClient.mustache +++ b/modules/swagger-codegen/src/main/resources/Java/libraries/okhttp-gson/ApiClient.mustache @@ -549,6 +549,17 @@ public class ApiClient { return params; } + /** + * Check if the given MIME is a JSON MIME. + * JSON MIME examples: + * application/json + * application/json; charset=UTF8 + * APPLICATION/JSON + */ + public boolean isJsonMime(String mime) { + return mime != null && mime.matches("(?i)application\\/json(;.*)?"); + } + /** * Select the Accept header's value from the given accepts array: * if JSON exists in the given array, use it; @@ -559,8 +570,14 @@ public class ApiClient { * null will be returned (not to set the Accept header explicitly). */ public String selectHeaderAccept(String[] accepts) { - if (accepts.length == 0) return null; - if (StringUtil.containsIgnoreCase(accepts, "application/json")) return "application/json"; + if (accepts.length == 0) { + return null; + } + for (String accept : accepts) { + if (isJsonMime(accept)) { + return accept; + } + } return StringUtil.join(accepts, ","); } @@ -574,8 +591,14 @@ public class ApiClient { * JSON will be used. */ public String selectHeaderContentType(String[] contentTypes) { - if (contentTypes.length == 0) return "application/json"; - if (StringUtil.containsIgnoreCase(contentTypes, "application/json")) return "application/json"; + if (contentTypes.length == 0) { + return "application/json"; + } + for (String contentType : contentTypes) { + if (isJsonMime(contentType)) { + return contentType; + } + } return contentTypes[0]; } @@ -626,7 +649,7 @@ public class ApiClient { // ensuring a default content type contentType = "application/json"; } - if (contentType.startsWith("application/json")) { + if (isJsonMime(contentType)) { return json.deserialize(respBody, returnType); } else if (returnType.equals(String.class)) { // Expecting string, return the raw response body. @@ -650,7 +673,7 @@ public class ApiClient { * @throws ApiException If fail to serialize the given object */ public String serialize(Object obj, String contentType) throws ApiException { - if (contentType.startsWith("application/json")) { + if (isJsonMime(contentType)) { if (obj != null) return json.serialize(obj); else @@ -822,7 +845,9 @@ public class ApiClient { String contentType = (String) headerParams.get("Content-Type"); // ensuring a default content type - if (contentType == null) contentType = "application/json"; + if (contentType == null) { + contentType = "application/json"; + } RequestBody reqBody; if (!HttpMethod.permitsRequestBody(method)) { diff --git a/samples/client/petstore/java/okhttp-gson/src/main/java/io/swagger/client/ApiClient.java b/samples/client/petstore/java/okhttp-gson/src/main/java/io/swagger/client/ApiClient.java index d4ee79cb3ad7..19cb83d620cb 100644 --- a/samples/client/petstore/java/okhttp-gson/src/main/java/io/swagger/client/ApiClient.java +++ b/samples/client/petstore/java/okhttp-gson/src/main/java/io/swagger/client/ApiClient.java @@ -548,6 +548,17 @@ public class ApiClient { return params; } + /** + * Check if the given MIME is a JSON MIME. + * JSON MIME examples: + * application/json + * application/json; charset=UTF8 + * APPLICATION/JSON + */ + public boolean isJsonMime(String mime) { + return mime != null && mime.matches("(?i)application\\/json(;.*)?"); + } + /** * Select the Accept header's value from the given accepts array: * if JSON exists in the given array, use it; @@ -558,8 +569,14 @@ public class ApiClient { * null will be returned (not to set the Accept header explicitly). */ public String selectHeaderAccept(String[] accepts) { - if (accepts.length == 0) return null; - if (StringUtil.containsIgnoreCase(accepts, "application/json")) return "application/json"; + if (accepts.length == 0) { + return null; + } + for (String accept : accepts) { + if (isJsonMime(accept)) { + return accept; + } + } return StringUtil.join(accepts, ","); } @@ -573,8 +590,14 @@ public class ApiClient { * JSON will be used. */ public String selectHeaderContentType(String[] contentTypes) { - if (contentTypes.length == 0) return "application/json"; - if (StringUtil.containsIgnoreCase(contentTypes, "application/json")) return "application/json"; + if (contentTypes.length == 0) { + return "application/json"; + } + for (String contentType : contentTypes) { + if (isJsonMime(contentType)) { + return contentType; + } + } return contentTypes[0]; } @@ -625,7 +648,7 @@ public class ApiClient { // ensuring a default content type contentType = "application/json"; } - if (contentType.startsWith("application/json")) { + if (isJsonMime(contentType)) { return json.deserialize(respBody, returnType); } else if (returnType.equals(String.class)) { // Expecting string, return the raw response body. @@ -649,7 +672,7 @@ public class ApiClient { * @throws ApiException If fail to serialize the given object */ public String serialize(Object obj, String contentType) throws ApiException { - if (contentType.startsWith("application/json")) { + if (isJsonMime(contentType)) { if (obj != null) return json.serialize(obj); else @@ -821,7 +844,9 @@ public class ApiClient { String contentType = (String) headerParams.get("Content-Type"); // ensuring a default content type - if (contentType == null) contentType = "application/json"; + if (contentType == null) { + contentType = "application/json"; + } RequestBody reqBody; if (!HttpMethod.permitsRequestBody(method)) { diff --git a/samples/client/petstore/java/okhttp-gson/src/test/java/io/swagger/client/ApiClientTest.java b/samples/client/petstore/java/okhttp-gson/src/test/java/io/swagger/client/ApiClientTest.java index aaf4f33c49ef..9b5c68057448 100644 --- a/samples/client/petstore/java/okhttp-gson/src/test/java/io/swagger/client/ApiClientTest.java +++ b/samples/client/petstore/java/okhttp-gson/src/test/java/io/swagger/client/ApiClientTest.java @@ -77,16 +77,29 @@ public class ApiClientTest { assertEquals(dateStr, apiClient.formatDate(apiClient.parseDate("2015-11"))); } + @Test + public void testIsJsonMime() { + assertFalse(apiClient.isJsonMime(null)); + assertFalse(apiClient.isJsonMime("")); + assertFalse(apiClient.isJsonMime("text/plain")); + assertFalse(apiClient.isJsonMime("application/xml")); + assertFalse(apiClient.isJsonMime("application/jsonp")); + + assertTrue(apiClient.isJsonMime("application/json")); + assertTrue(apiClient.isJsonMime("application/json; charset=UTF8")); + assertTrue(apiClient.isJsonMime("APPLICATION/JSON")); + } + @Test public void testSelectHeaderAccept() { - String[] accepts = {"APPLICATION/JSON", "APPLICATION/XML"}; + String[] accepts = {"application/json", "application/xml"}; assertEquals("application/json", apiClient.selectHeaderAccept(accepts)); - accepts = new String[]{"application/json", "application/xml"}; - assertEquals("application/json", apiClient.selectHeaderAccept(accepts)); + accepts = new String[]{"APPLICATION/XML", "APPLICATION/JSON"}; + assertEquals("APPLICATION/JSON", apiClient.selectHeaderAccept(accepts)); - accepts = new String[]{"application/xml", "application/json"}; - assertEquals("application/json", apiClient.selectHeaderAccept(accepts)); + accepts = new String[]{"application/xml", "application/json; charset=UTF8"}; + assertEquals("application/json; charset=UTF8", apiClient.selectHeaderAccept(accepts)); accepts = new String[]{"text/plain", "application/xml"}; assertEquals("text/plain,application/xml", apiClient.selectHeaderAccept(accepts)); @@ -97,14 +110,14 @@ public class ApiClientTest { @Test public void testSelectHeaderContentType() { - String[] contentTypes = {"APPLICATION/JSON", "APPLICATION/XML"}; + String[] contentTypes = {"application/json", "application/xml"}; assertEquals("application/json", apiClient.selectHeaderContentType(contentTypes)); - contentTypes = new String[]{"application/json", "application/xml"}; - assertEquals("application/json", apiClient.selectHeaderContentType(contentTypes)); + contentTypes = new String[]{"APPLICATION/JSON", "APPLICATION/XML"}; + assertEquals("APPLICATION/JSON", apiClient.selectHeaderContentType(contentTypes)); - contentTypes = new String[]{"application/xml", "application/json"}; - assertEquals("application/json", apiClient.selectHeaderContentType(contentTypes)); + contentTypes = new String[]{"application/xml", "application/json; charset=UTF8"}; + assertEquals("application/json; charset=UTF8", apiClient.selectHeaderContentType(contentTypes)); contentTypes = new String[]{"text/plain", "application/xml"}; assertEquals("text/plain", apiClient.selectHeaderContentType(contentTypes)); From e767a7d6d812d976edde3478ef0cc4893c793b15 Mon Sep 17 00:00:00 2001 From: wing328 Date: Wed, 9 Dec 2015 16:21:00 +0800 Subject: [PATCH 26/71] add default value to objc model properties --- .../codegen/languages/ObjcClientCodegen.java | 60 ++++++++++++++++--- .../main/resources/objc/model-body.mustache | 11 ++++ .../petstore/objc/SwaggerClient/SWGCategory.m | 10 ++++ .../petstore/objc/SwaggerClient/SWGOrder.m | 10 ++++ .../petstore/objc/SwaggerClient/SWGPet.m | 10 ++++ .../petstore/objc/SwaggerClient/SWGTag.m | 10 ++++ .../petstore/objc/SwaggerClient/SWGUser.m | 10 ++++ 7 files changed, 113 insertions(+), 8 deletions(-) diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ObjcClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ObjcClientCodegen.java index 7037ee06f9b3..9c488db1254a 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ObjcClientCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ObjcClientCodegen.java @@ -7,9 +7,7 @@ import io.swagger.codegen.CodegenProperty; import io.swagger.codegen.CodegenType; import io.swagger.codegen.DefaultCodegen; import io.swagger.codegen.SupportingFile; -import io.swagger.models.properties.ArrayProperty; -import io.swagger.models.properties.MapProperty; -import io.swagger.models.properties.Property; +import io.swagger.models.properties.*; import java.io.File; import java.util.Arrays; @@ -343,11 +341,6 @@ public class ObjcClientCodegen extends DefaultCodegen implements CodegenConfig { return name; } - @Override - public String toDefaultValue(Property p) { - return null; - } - @Override public String apiFileFolder() { return outputFolder + File.separatorChar + apiPackage(); @@ -452,4 +445,55 @@ public class ObjcClientCodegen extends DefaultCodegen implements CodegenConfig { public void setLicense(String license) { this.license = license; } + + /** + * Return the default value of the property + * + * @param p Swagger property object + * @return string presentation of the default value of the property + */ + @Override + public String toDefaultValue(Property p) { + if (p instanceof StringProperty) { + StringProperty dp = (StringProperty) p; + if (dp.getDefault() != null) { + return "@\"" + dp.getDefault().toString() + "\""; + } + } else if (p instanceof BooleanProperty) { + BooleanProperty dp = (BooleanProperty) p; + if (dp.getDefault() != null) { + if (dp.getDefault().toString().equalsIgnoreCase("false")) + return "@0"; + else + return "@1"; + } + } else if (p instanceof DateProperty) { + // TODO + } else if (p instanceof DateTimeProperty) { + // TODO + } else if (p instanceof DoubleProperty) { + DoubleProperty dp = (DoubleProperty) p; + if (dp.getDefault() != null) { + return "@" + dp.getDefault().toString(); + } + } else if (p instanceof FloatProperty) { + FloatProperty dp = (FloatProperty) p; + if (dp.getDefault() != null) { + return "@" + dp.getDefault().toString(); + } + } else if (p instanceof IntegerProperty) { + IntegerProperty dp = (IntegerProperty) p; + if (dp.getDefault() != null) { + return "@" + dp.getDefault().toString(); + } + } else if (p instanceof LongProperty) { + LongProperty dp = (LongProperty) p; + if (dp.getDefault() != null) { + return "@" + dp.getDefault().toString(); + } + } + + return null; + } + } diff --git a/modules/swagger-codegen/src/main/resources/objc/model-body.mustache b/modules/swagger-codegen/src/main/resources/objc/model-body.mustache index 33c0f8cf42b5..ba76b12aeb89 100644 --- a/modules/swagger-codegen/src/main/resources/objc/model-body.mustache +++ b/modules/swagger-codegen/src/main/resources/objc/model-body.mustache @@ -4,6 +4,17 @@ @implementation {{classname}} +- (instancetype)init { + self = [super init]; + if (self) + { + // initalise property's default value, if any + {{#vars}}{{#defaultValue}}self.{{name}} = {{{defaultValue}}}; + {{/defaultValue}}{{/vars}} + } + return self; +} + /** * Maps json key to property name. * This method is used by `JSONModel`. diff --git a/samples/client/petstore/objc/SwaggerClient/SWGCategory.m b/samples/client/petstore/objc/SwaggerClient/SWGCategory.m index fb3ccecf1760..7c71e4af0f45 100644 --- a/samples/client/petstore/objc/SwaggerClient/SWGCategory.m +++ b/samples/client/petstore/objc/SwaggerClient/SWGCategory.m @@ -2,6 +2,16 @@ @implementation SWGCategory +- (instancetype)init { + self = [super init]; + if (self) + { + // initalise property's default value, if any + + } + return self; +} + /** * Maps json key to property name. * This method is used by `JSONModel`. diff --git a/samples/client/petstore/objc/SwaggerClient/SWGOrder.m b/samples/client/petstore/objc/SwaggerClient/SWGOrder.m index 83fe5741cd7f..ba0b637eb09a 100644 --- a/samples/client/petstore/objc/SwaggerClient/SWGOrder.m +++ b/samples/client/petstore/objc/SwaggerClient/SWGOrder.m @@ -2,6 +2,16 @@ @implementation SWGOrder +- (instancetype)init { + self = [super init]; + if (self) + { + // initalise property's default value, if any + + } + return self; +} + /** * Maps json key to property name. * This method is used by `JSONModel`. diff --git a/samples/client/petstore/objc/SwaggerClient/SWGPet.m b/samples/client/petstore/objc/SwaggerClient/SWGPet.m index 3fd315ab0118..388157eb0cc6 100644 --- a/samples/client/petstore/objc/SwaggerClient/SWGPet.m +++ b/samples/client/petstore/objc/SwaggerClient/SWGPet.m @@ -2,6 +2,16 @@ @implementation SWGPet +- (instancetype)init { + self = [super init]; + if (self) + { + // initalise property's default value, if any + + } + return self; +} + /** * Maps json key to property name. * This method is used by `JSONModel`. diff --git a/samples/client/petstore/objc/SwaggerClient/SWGTag.m b/samples/client/petstore/objc/SwaggerClient/SWGTag.m index 3bcb9973dfd2..7a7e7550debb 100644 --- a/samples/client/petstore/objc/SwaggerClient/SWGTag.m +++ b/samples/client/petstore/objc/SwaggerClient/SWGTag.m @@ -2,6 +2,16 @@ @implementation SWGTag +- (instancetype)init { + self = [super init]; + if (self) + { + // initalise property's default value, if any + + } + return self; +} + /** * Maps json key to property name. * This method is used by `JSONModel`. diff --git a/samples/client/petstore/objc/SwaggerClient/SWGUser.m b/samples/client/petstore/objc/SwaggerClient/SWGUser.m index d040a6bce6da..bdb26cf36a62 100644 --- a/samples/client/petstore/objc/SwaggerClient/SWGUser.m +++ b/samples/client/petstore/objc/SwaggerClient/SWGUser.m @@ -2,6 +2,16 @@ @implementation SWGUser +- (instancetype)init { + self = [super init]; + if (self) + { + // initalise property's default value, if any + + } + return self; +} + /** * Maps json key to property name. * This method is used by `JSONModel`. From be0bc71c863a2c5a7e3dca5c55853311d61f7db5 Mon Sep 17 00:00:00 2001 From: xhh Date: Wed, 9 Dec 2015 16:30:55 +0800 Subject: [PATCH 27/71] Improve checking of JSON MIME in Java default and jersey2 to support suffix like charset in "application/json; charset=UTF8" --- .../main/resources/Java/ApiClient.mustache | 35 +++++++++++++++--- .../Java/libraries/jersey2/ApiClient.mustache | 35 +++++++++++++++--- .../java/io/swagger/client/ApiClient.java | 37 +++++++++++++++---- .../java/io/swagger/client/ApiClientTest.java | 33 ++++++++++++----- .../java/io/swagger/client/ApiClient.java | 37 +++++++++++++++---- .../java/io/swagger/client/ApiClientTest.java | 33 ++++++++++++----- 6 files changed, 164 insertions(+), 46 deletions(-) diff --git a/modules/swagger-codegen/src/main/resources/Java/ApiClient.mustache b/modules/swagger-codegen/src/main/resources/Java/ApiClient.mustache index 2e73cd702e90..562df7e1f796 100644 --- a/modules/swagger-codegen/src/main/resources/Java/ApiClient.mustache +++ b/modules/swagger-codegen/src/main/resources/Java/ApiClient.mustache @@ -337,6 +337,17 @@ public class ApiClient { return params; } + /** + * Check if the given MIME is a JSON MIME. + * JSON MIME examples: + * application/json + * application/json; charset=UTF8 + * APPLICATION/JSON + */ + public boolean isJsonMime(String mime) { + return mime != null && mime.matches("(?i)application\\/json(;.*)?"); + } + /** * Select the Accept header's value from the given accepts array: * if JSON exists in the given array, use it; @@ -347,8 +358,14 @@ public class ApiClient { * null will be returned (not to set the Accept header explicitly). */ public String selectHeaderAccept(String[] accepts) { - if (accepts.length == 0) return null; - if (StringUtil.containsIgnoreCase(accepts, "application/json")) return "application/json"; + if (accepts.length == 0) { + return null; + } + for (String accept : accepts) { + if (isJsonMime(accept)) { + return accept; + } + } return StringUtil.join(accepts, ","); } @@ -362,8 +379,14 @@ public class ApiClient { * JSON will be used. */ public String selectHeaderContentType(String[] contentTypes) { - if (contentTypes.length == 0) return "application/json"; - if (StringUtil.containsIgnoreCase(contentTypes, "application/json")) return "application/json"; + if (contentTypes.length == 0) { + return "application/json"; + } + for (String contentType : contentTypes) { + if (isJsonMime(contentType)) { + return contentType; + } + } return contentTypes[0]; } @@ -383,7 +406,7 @@ public class ApiClient { * Content-Type (only JSON is supported for now). */ public String serialize(Object obj, String contentType) throws ApiException { - if (contentType.startsWith("application/json")) { + if (isJsonMime(contentType)) { return json.serialize(obj); } else { throw new ApiException(400, "can not serialize object into Content-Type: " + contentType); @@ -407,7 +430,7 @@ public class ApiClient { else body = ""; - if (contentType.startsWith("application/json")) { + if (isJsonMime(contentType)) { return json.deserialize(body, returnType); } else if (returnType.getType().equals(String.class)) { // Expecting string, return the raw response body. diff --git a/modules/swagger-codegen/src/main/resources/Java/libraries/jersey2/ApiClient.mustache b/modules/swagger-codegen/src/main/resources/Java/libraries/jersey2/ApiClient.mustache index d29beeea34cc..4f08158ab759 100644 --- a/modules/swagger-codegen/src/main/resources/Java/libraries/jersey2/ApiClient.mustache +++ b/modules/swagger-codegen/src/main/resources/Java/libraries/jersey2/ApiClient.mustache @@ -344,6 +344,17 @@ public class ApiClient { return params; } + /** + * Check if the given MIME is a JSON MIME. + * JSON MIME examples: + * application/json + * application/json; charset=UTF8 + * APPLICATION/JSON + */ + public boolean isJsonMime(String mime) { + return mime != null && mime.matches("(?i)application\\/json(;.*)?"); + } + /** * Select the Accept header's value from the given accepts array: * if JSON exists in the given array, use it; @@ -354,8 +365,14 @@ public class ApiClient { * null will be returned (not to set the Accept header explicitly). */ public String selectHeaderAccept(String[] accepts) { - if (accepts.length == 0) return null; - if (StringUtil.containsIgnoreCase(accepts, "application/json")) return "application/json"; + if (accepts.length == 0) { + return null; + } + for (String accept : accepts) { + if (isJsonMime(accept)) { + return accept; + } + } return StringUtil.join(accepts, ","); } @@ -369,8 +386,14 @@ public class ApiClient { * JSON will be used. */ public String selectHeaderContentType(String[] contentTypes) { - if (contentTypes.length == 0) return "application/json"; - if (StringUtil.containsIgnoreCase(contentTypes, "application/json")) return "application/json"; + if (contentTypes.length == 0) { + return "application/json"; + } + for (String contentType : contentTypes) { + if (isJsonMime(contentType)) { + return contentType; + } + } return contentTypes[0]; } @@ -390,7 +413,7 @@ public class ApiClient { * Content-Type (only JSON is supported for now). */ public Entity serialize(Object obj, String contentType) throws ApiException { - if (contentType.startsWith("application/json")) { + if (isJsonMime(contentType)) { return Entity.json(json.serialize(obj)); } else { throw new ApiException(400, "can not serialize object into Content-Type: " + contentType); @@ -414,7 +437,7 @@ public class ApiClient { else body = ""; - if (contentType.startsWith("application/json")) { + if (isJsonMime(contentType)) { return json.deserialize(body, returnType); } else if (returnType.getType().equals(String.class)) { // Expecting string, return the raw response body. diff --git a/samples/client/petstore/java/default/src/main/java/io/swagger/client/ApiClient.java b/samples/client/petstore/java/default/src/main/java/io/swagger/client/ApiClient.java index 1966b0a34c65..3d40225c78f6 100644 --- a/samples/client/petstore/java/default/src/main/java/io/swagger/client/ApiClient.java +++ b/samples/client/petstore/java/default/src/main/java/io/swagger/client/ApiClient.java @@ -39,7 +39,7 @@ import io.swagger.client.auth.HttpBasicAuth; import io.swagger.client.auth.ApiKeyAuth; import io.swagger.client.auth.OAuth; -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-02T18:29:05.463+08:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-09T16:17:57.986+08:00") public class ApiClient { private Map hostMap = new HashMap(); private Map defaultHeaderMap = new HashMap(); @@ -336,6 +336,17 @@ public class ApiClient { return params; } + /** + * Check if the given MIME is a JSON MIME. + * JSON MIME examples: + * application/json + * application/json; charset=UTF8 + * APPLICATION/JSON + */ + public boolean isJsonMime(String mime) { + return mime != null && mime.matches("(?i)application\\/json(;.*)?"); + } + /** * Select the Accept header's value from the given accepts array: * if JSON exists in the given array, use it; @@ -346,8 +357,14 @@ public class ApiClient { * null will be returned (not to set the Accept header explicitly). */ public String selectHeaderAccept(String[] accepts) { - if (accepts.length == 0) return null; - if (StringUtil.containsIgnoreCase(accepts, "application/json")) return "application/json"; + if (accepts.length == 0) { + return null; + } + for (String accept : accepts) { + if (isJsonMime(accept)) { + return accept; + } + } return StringUtil.join(accepts, ","); } @@ -361,8 +378,14 @@ public class ApiClient { * JSON will be used. */ public String selectHeaderContentType(String[] contentTypes) { - if (contentTypes.length == 0) return "application/json"; - if (StringUtil.containsIgnoreCase(contentTypes, "application/json")) return "application/json"; + if (contentTypes.length == 0) { + return "application/json"; + } + for (String contentType : contentTypes) { + if (isJsonMime(contentType)) { + return contentType; + } + } return contentTypes[0]; } @@ -382,7 +405,7 @@ public class ApiClient { * Content-Type (only JSON is supported for now). */ public String serialize(Object obj, String contentType) throws ApiException { - if (contentType.startsWith("application/json")) { + if (isJsonMime(contentType)) { return json.serialize(obj); } else { throw new ApiException(400, "can not serialize object into Content-Type: " + contentType); @@ -406,7 +429,7 @@ public class ApiClient { else body = ""; - if (contentType.startsWith("application/json")) { + if (isJsonMime(contentType)) { return json.deserialize(body, returnType); } else if (returnType.getType().equals(String.class)) { // Expecting string, return the raw response body. diff --git a/samples/client/petstore/java/default/src/test/java/io/swagger/client/ApiClientTest.java b/samples/client/petstore/java/default/src/test/java/io/swagger/client/ApiClientTest.java index 3d57f3fa84cf..29eae3d017ea 100644 --- a/samples/client/petstore/java/default/src/test/java/io/swagger/client/ApiClientTest.java +++ b/samples/client/petstore/java/default/src/test/java/io/swagger/client/ApiClientTest.java @@ -38,16 +38,29 @@ public class ApiClientTest { assertEquals(dateStr, apiClient.formatDate(apiClient.parseDate("2015-11-07T13:49:09+10:00"))); } + @Test + public void testIsJsonMime() { + assertFalse(apiClient.isJsonMime(null)); + assertFalse(apiClient.isJsonMime("")); + assertFalse(apiClient.isJsonMime("text/plain")); + assertFalse(apiClient.isJsonMime("application/xml")); + assertFalse(apiClient.isJsonMime("application/jsonp")); + + assertTrue(apiClient.isJsonMime("application/json")); + assertTrue(apiClient.isJsonMime("application/json; charset=UTF8")); + assertTrue(apiClient.isJsonMime("APPLICATION/JSON")); + } + @Test public void testSelectHeaderAccept() { - String[] accepts = {"APPLICATION/JSON", "APPLICATION/XML"}; + String[] accepts = {"application/json", "application/xml"}; assertEquals("application/json", apiClient.selectHeaderAccept(accepts)); - accepts = new String[]{"application/json", "application/xml"}; - assertEquals("application/json", apiClient.selectHeaderAccept(accepts)); + accepts = new String[]{"APPLICATION/XML", "APPLICATION/JSON"}; + assertEquals("APPLICATION/JSON", apiClient.selectHeaderAccept(accepts)); - accepts = new String[]{"application/xml", "application/json"}; - assertEquals("application/json", apiClient.selectHeaderAccept(accepts)); + accepts = new String[]{"application/xml", "application/json; charset=UTF8"}; + assertEquals("application/json; charset=UTF8", apiClient.selectHeaderAccept(accepts)); accepts = new String[]{"text/plain", "application/xml"}; assertEquals("text/plain,application/xml", apiClient.selectHeaderAccept(accepts)); @@ -58,14 +71,14 @@ public class ApiClientTest { @Test public void testSelectHeaderContentType() { - String[] contentTypes = {"APPLICATION/JSON", "APPLICATION/XML"}; + String[] contentTypes = {"application/json", "application/xml"}; assertEquals("application/json", apiClient.selectHeaderContentType(contentTypes)); - contentTypes = new String[]{"application/json", "application/xml"}; - assertEquals("application/json", apiClient.selectHeaderContentType(contentTypes)); + contentTypes = new String[]{"APPLICATION/JSON", "APPLICATION/XML"}; + assertEquals("APPLICATION/JSON", apiClient.selectHeaderContentType(contentTypes)); - contentTypes = new String[]{"application/xml", "application/json"}; - assertEquals("application/json", apiClient.selectHeaderContentType(contentTypes)); + contentTypes = new String[]{"application/xml", "application/json; charset=UTF8"}; + assertEquals("application/json; charset=UTF8", apiClient.selectHeaderContentType(contentTypes)); contentTypes = new String[]{"text/plain", "application/xml"}; assertEquals("text/plain", apiClient.selectHeaderContentType(contentTypes)); diff --git a/samples/client/petstore/java/jersey2/src/main/java/io/swagger/client/ApiClient.java b/samples/client/petstore/java/jersey2/src/main/java/io/swagger/client/ApiClient.java index e9c55bfb710f..c5c74cc11e4e 100644 --- a/samples/client/petstore/java/jersey2/src/main/java/io/swagger/client/ApiClient.java +++ b/samples/client/petstore/java/jersey2/src/main/java/io/swagger/client/ApiClient.java @@ -42,7 +42,7 @@ import io.swagger.client.auth.HttpBasicAuth; import io.swagger.client.auth.ApiKeyAuth; import io.swagger.client.auth.OAuth; -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-02T18:29:08.393+08:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-09T16:27:55.818+08:00") public class ApiClient { private Client client; private Map hostMap = new HashMap(); @@ -343,6 +343,17 @@ public class ApiClient { return params; } + /** + * Check if the given MIME is a JSON MIME. + * JSON MIME examples: + * application/json + * application/json; charset=UTF8 + * APPLICATION/JSON + */ + public boolean isJsonMime(String mime) { + return mime != null && mime.matches("(?i)application\\/json(;.*)?"); + } + /** * Select the Accept header's value from the given accepts array: * if JSON exists in the given array, use it; @@ -353,8 +364,14 @@ public class ApiClient { * null will be returned (not to set the Accept header explicitly). */ public String selectHeaderAccept(String[] accepts) { - if (accepts.length == 0) return null; - if (StringUtil.containsIgnoreCase(accepts, "application/json")) return "application/json"; + if (accepts.length == 0) { + return null; + } + for (String accept : accepts) { + if (isJsonMime(accept)) { + return accept; + } + } return StringUtil.join(accepts, ","); } @@ -368,8 +385,14 @@ public class ApiClient { * JSON will be used. */ public String selectHeaderContentType(String[] contentTypes) { - if (contentTypes.length == 0) return "application/json"; - if (StringUtil.containsIgnoreCase(contentTypes, "application/json")) return "application/json"; + if (contentTypes.length == 0) { + return "application/json"; + } + for (String contentType : contentTypes) { + if (isJsonMime(contentType)) { + return contentType; + } + } return contentTypes[0]; } @@ -389,7 +412,7 @@ public class ApiClient { * Content-Type (only JSON is supported for now). */ public Entity serialize(Object obj, String contentType) throws ApiException { - if (contentType.startsWith("application/json")) { + if (isJsonMime(contentType)) { return Entity.json(json.serialize(obj)); } else { throw new ApiException(400, "can not serialize object into Content-Type: " + contentType); @@ -413,7 +436,7 @@ public class ApiClient { else body = ""; - if (contentType.startsWith("application/json")) { + if (isJsonMime(contentType)) { return json.deserialize(body, returnType); } else if (returnType.getType().equals(String.class)) { // Expecting string, return the raw response body. diff --git a/samples/client/petstore/java/jersey2/src/test/java/io/swagger/client/ApiClientTest.java b/samples/client/petstore/java/jersey2/src/test/java/io/swagger/client/ApiClientTest.java index 3d57f3fa84cf..29eae3d017ea 100644 --- a/samples/client/petstore/java/jersey2/src/test/java/io/swagger/client/ApiClientTest.java +++ b/samples/client/petstore/java/jersey2/src/test/java/io/swagger/client/ApiClientTest.java @@ -38,16 +38,29 @@ public class ApiClientTest { assertEquals(dateStr, apiClient.formatDate(apiClient.parseDate("2015-11-07T13:49:09+10:00"))); } + @Test + public void testIsJsonMime() { + assertFalse(apiClient.isJsonMime(null)); + assertFalse(apiClient.isJsonMime("")); + assertFalse(apiClient.isJsonMime("text/plain")); + assertFalse(apiClient.isJsonMime("application/xml")); + assertFalse(apiClient.isJsonMime("application/jsonp")); + + assertTrue(apiClient.isJsonMime("application/json")); + assertTrue(apiClient.isJsonMime("application/json; charset=UTF8")); + assertTrue(apiClient.isJsonMime("APPLICATION/JSON")); + } + @Test public void testSelectHeaderAccept() { - String[] accepts = {"APPLICATION/JSON", "APPLICATION/XML"}; + String[] accepts = {"application/json", "application/xml"}; assertEquals("application/json", apiClient.selectHeaderAccept(accepts)); - accepts = new String[]{"application/json", "application/xml"}; - assertEquals("application/json", apiClient.selectHeaderAccept(accepts)); + accepts = new String[]{"APPLICATION/XML", "APPLICATION/JSON"}; + assertEquals("APPLICATION/JSON", apiClient.selectHeaderAccept(accepts)); - accepts = new String[]{"application/xml", "application/json"}; - assertEquals("application/json", apiClient.selectHeaderAccept(accepts)); + accepts = new String[]{"application/xml", "application/json; charset=UTF8"}; + assertEquals("application/json; charset=UTF8", apiClient.selectHeaderAccept(accepts)); accepts = new String[]{"text/plain", "application/xml"}; assertEquals("text/plain,application/xml", apiClient.selectHeaderAccept(accepts)); @@ -58,14 +71,14 @@ public class ApiClientTest { @Test public void testSelectHeaderContentType() { - String[] contentTypes = {"APPLICATION/JSON", "APPLICATION/XML"}; + String[] contentTypes = {"application/json", "application/xml"}; assertEquals("application/json", apiClient.selectHeaderContentType(contentTypes)); - contentTypes = new String[]{"application/json", "application/xml"}; - assertEquals("application/json", apiClient.selectHeaderContentType(contentTypes)); + contentTypes = new String[]{"APPLICATION/JSON", "APPLICATION/XML"}; + assertEquals("APPLICATION/JSON", apiClient.selectHeaderContentType(contentTypes)); - contentTypes = new String[]{"application/xml", "application/json"}; - assertEquals("application/json", apiClient.selectHeaderContentType(contentTypes)); + contentTypes = new String[]{"application/xml", "application/json; charset=UTF8"}; + assertEquals("application/json; charset=UTF8", apiClient.selectHeaderContentType(contentTypes)); contentTypes = new String[]{"text/plain", "application/xml"}; assertEquals("text/plain", apiClient.selectHeaderContentType(contentTypes)); From ba48f8712d53f910a847c8da6b158ff6efa28adb Mon Sep 17 00:00:00 2001 From: xhh Date: Wed, 9 Dec 2015 16:34:53 +0800 Subject: [PATCH 28/71] Add test case for the "json_mime?" method --- samples/client/petstore/ruby/spec/api_client_spec.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/client/petstore/ruby/spec/api_client_spec.rb b/samples/client/petstore/ruby/spec/api_client_spec.rb index 054f63bc4ef8..7b2478ea67c3 100644 --- a/samples/client/petstore/ruby/spec/api_client_spec.rb +++ b/samples/client/petstore/ruby/spec/api_client_spec.rb @@ -158,6 +158,7 @@ describe Petstore::ApiClient do api_client.json_mime?('application/xml').should == false api_client.json_mime?('text/plain').should == false + api_client.json_mime?('application/jsonp').should == false end end From 8e0816b5dd8773c98bd833fa172f1f83f42dcb14 Mon Sep 17 00:00:00 2001 From: thibaultclem Date: Wed, 9 Dec 2015 16:11:08 +0700 Subject: [PATCH 29/71] Fix syntax issue when generating Javascript client operation without parameters --- .../swagger-codegen/src/main/resources/Javascript/api.mustache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/swagger-codegen/src/main/resources/Javascript/api.mustache b/modules/swagger-codegen/src/main/resources/Javascript/api.mustache index a9af0d54c15a..f7bc498ff189 100644 --- a/modules/swagger-codegen/src/main/resources/Javascript/api.mustache +++ b/modules/swagger-codegen/src/main/resources/Javascript/api.mustache @@ -20,7 +20,7 @@ var {{classname}} = function {{classname}}() { {{/allParams}} * @param {function} callback the callback function * @return {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}} */ - self.{{nickname}} = function({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}, callback) { + self.{{nickname}} = function({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}{{#hasParams}}, {{/hasParams}}callback) { var {{localVariablePrefix}}postBody = {{#bodyParam}}{{^isBinary}}JSON.stringify({{paramName}}){{/isBinary}}{{#isBinary}}null{{/isBinary}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}}; var {{localVariablePrefix}}postBinaryBody = {{#bodyParam}}{{#isBinary}}{{paramName}}{{/isBinary}}{{^isBinary}}null{{/isBinary}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}}; From 7c7255278082337f69971844f734e7022a5e269b Mon Sep 17 00:00:00 2001 From: thibaultclem Date: Wed, 9 Dec 2015 16:32:18 +0700 Subject: [PATCH 30/71] Update JS Client Petstore samples after fixing issue on the JS api.mustache --- .../client/petstore/javascript/src/scripts/rest/api/PetApi.js | 2 +- .../petstore/javascript/src/scripts/rest/api/StoreApi.js | 4 ++-- .../petstore/javascript/src/scripts/rest/api/UserApi.js | 4 ++-- .../client/petstore/javascript/src/scripts/rest/model/Pet.js | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/samples/client/petstore/javascript/src/scripts/rest/api/PetApi.js b/samples/client/petstore/javascript/src/scripts/rest/api/PetApi.js index a693d83dbc2d..bf35463dc1a5 100644 --- a/samples/client/petstore/javascript/src/scripts/rest/api/PetApi.js +++ b/samples/client/petstore/javascript/src/scripts/rest/api/PetApi.js @@ -1,5 +1,5 @@ /* - * @javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavascriptClientCodegen", date = "2015-12-07T10:51:19.835+08:00") + * @javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavascriptClientCodegen", date = "2015-12-09T16:07:21.000+07:00") */ //export module diff --git a/samples/client/petstore/javascript/src/scripts/rest/api/StoreApi.js b/samples/client/petstore/javascript/src/scripts/rest/api/StoreApi.js index 086ce8b4ae9a..5487b1c386ed 100644 --- a/samples/client/petstore/javascript/src/scripts/rest/api/StoreApi.js +++ b/samples/client/petstore/javascript/src/scripts/rest/api/StoreApi.js @@ -1,5 +1,5 @@ /* - * @javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavascriptClientCodegen", date = "2015-12-07T10:51:19.835+08:00") + * @javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavascriptClientCodegen", date = "2015-12-09T16:07:21.000+07:00") */ //export module @@ -18,7 +18,7 @@ var StoreApi = function StoreApi() { * @param {function} callback the callback function * @return Map */ - self.getInventory = function(, callback) { + self.getInventory = function(callback) { var postBody = null; var postBinaryBody = null; diff --git a/samples/client/petstore/javascript/src/scripts/rest/api/UserApi.js b/samples/client/petstore/javascript/src/scripts/rest/api/UserApi.js index 53cecbdf8f74..30c797cf25f2 100644 --- a/samples/client/petstore/javascript/src/scripts/rest/api/UserApi.js +++ b/samples/client/petstore/javascript/src/scripts/rest/api/UserApi.js @@ -1,5 +1,5 @@ /* - * @javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavascriptClientCodegen", date = "2015-12-07T10:51:19.835+08:00") + * @javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavascriptClientCodegen", date = "2015-12-09T16:07:21.000+07:00") */ //export module @@ -230,7 +230,7 @@ var UserApi = function UserApi() { * @param {function} callback the callback function * @return void */ - self.logoutUser = function(, callback) { + self.logoutUser = function(callback) { var postBody = null; var postBinaryBody = null; diff --git a/samples/client/petstore/javascript/src/scripts/rest/model/Pet.js b/samples/client/petstore/javascript/src/scripts/rest/model/Pet.js index e3f3a747c84c..b97907396f18 100644 --- a/samples/client/petstore/javascript/src/scripts/rest/model/Pet.js +++ b/samples/client/petstore/javascript/src/scripts/rest/model/Pet.js @@ -38,7 +38,7 @@ if ( typeof define === "function" && define.amd ) { } -var Pet = function Pet(name, photoUrls) { +var Pet = function Pet(photoUrls, name) { var self = this; /** From 63092b89237be6577895848230db1976c5a5af48 Mon Sep 17 00:00:00 2001 From: xhh Date: Wed, 9 Dec 2015 22:55:49 +0800 Subject: [PATCH 31/71] Clojure client: use case-insensitive checking on JSON MIME --- .../src/main/resources/clojure/core.mustache | 2 +- .../client/petstore/clojure/src/swagger_petstore/core.clj | 2 +- .../petstore/clojure/test/swagger_petstore/core_test.clj | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/modules/swagger-codegen/src/main/resources/clojure/core.mustache b/modules/swagger-codegen/src/main/resources/clojure/core.mustache index 79d0ee9b5eec..0da2a4514954 100644 --- a/modules/swagger-codegen/src/main/resources/clojure/core.mustache +++ b/modules/swagger-codegen/src/main/resources/clojure/core.mustache @@ -174,7 +174,7 @@ [mime] (if mime (or (= :json mime) - (re-matches #"application/json(;.*)?" (name mime))))) + (re-matches #"(?i)application/json(;.*)?" (name mime))))) (defn json-preferred-mime "Choose a MIME from the given MIMEs with JSON preferred, diff --git a/samples/client/petstore/clojure/src/swagger_petstore/core.clj b/samples/client/petstore/clojure/src/swagger_petstore/core.clj index 4c8a84269681..665adfbc775c 100644 --- a/samples/client/petstore/clojure/src/swagger_petstore/core.clj +++ b/samples/client/petstore/clojure/src/swagger_petstore/core.clj @@ -174,7 +174,7 @@ [mime] (if mime (or (= :json mime) - (re-matches #"application/json(;.*)?" (name mime))))) + (re-matches #"(?i)application/json(;.*)?" (name mime))))) (defn json-preferred-mime "Choose a MIME from the given MIMEs with JSON preferred, diff --git a/samples/client/petstore/clojure/test/swagger_petstore/core_test.clj b/samples/client/petstore/clojure/test/swagger_petstore/core_test.clj index 27a9e1db2910..87ac0a8b73dd 100644 --- a/samples/client/petstore/clojure/test/swagger_petstore/core_test.clj +++ b/samples/client/petstore/clojure/test/swagger_petstore/core_test.clj @@ -151,10 +151,12 @@ (is (= expected (boolean (json-mime? mime)))) :json true "application/json" true + "APPLICATION/JSON" true "application/json; charset=utf8" true nil false :xml false - "application/pdf" false)) + "application/pdf" false + "application/jsonp" false)) (deftest test-json-preferred-mime (are [mimes expected] @@ -177,4 +179,4 @@ "{\"aa\": 1, \"bb\": \"2\"}" "application/json" {:aa 1 :bb "2"} "[1, \"2\"]" "application/json; charset=UTF8" [1 "2"] "{invalid json}" "application/json" "{invalid json}" - "plain text" "text/plain" "plain text")) \ No newline at end of file + "plain text" "text/plain" "plain text")) From 0d19b30c9967275ad1ed217bf833ad74a5e0c4cd Mon Sep 17 00:00:00 2001 From: David Kiss Date: Wed, 9 Dec 2015 23:12:42 -0500 Subject: [PATCH 32/71] using isBodyParam instead of vendorExtention.x-isBody --- .../java/io/swagger/codegen/languages/JavaClientCodegen.java | 1 - .../src/main/resources/Java/libraries/feign/api.mustache | 2 +- .../java/feign/src/main/java/io/swagger/client/ApiClient.java | 2 +- .../feign/src/main/java/io/swagger/client/FormAwareEncoder.java | 2 +- .../java/feign/src/main/java/io/swagger/client/StringUtil.java | 2 +- .../java/feign/src/main/java/io/swagger/client/api/PetApi.java | 2 +- .../feign/src/main/java/io/swagger/client/api/StoreApi.java | 2 +- .../java/feign/src/main/java/io/swagger/client/api/UserApi.java | 2 +- .../src/main/java/io/swagger/client/model/ApiResponse.java | 2 +- .../feign/src/main/java/io/swagger/client/model/Category.java | 2 +- .../java/feign/src/main/java/io/swagger/client/model/Order.java | 2 +- .../java/feign/src/main/java/io/swagger/client/model/Pet.java | 2 +- .../java/feign/src/main/java/io/swagger/client/model/Tag.java | 2 +- .../java/feign/src/main/java/io/swagger/client/model/User.java | 2 +- 14 files changed, 13 insertions(+), 14 deletions(-) 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 b12894a73003..254bedf4708d 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 @@ -560,7 +560,6 @@ public class JavaClientCodegen extends DefaultCodegen implements CodegenConfig { for (Operation operation : path.getOperations()) { boolean hasFormParameters = false; for (Parameter parameter : operation.getParameters()) { - parameter.getVendorExtensions().put("x-isBody", parameter instanceof BodyParameter); if (parameter instanceof FormParameter) { hasFormParameters = true; } diff --git a/modules/swagger-codegen/src/main/resources/Java/libraries/feign/api.mustache b/modules/swagger-codegen/src/main/resources/Java/libraries/feign/api.mustache index 30c8a793914e..729320bd2e5c 100644 --- a/modules/swagger-codegen/src/main/resources/Java/libraries/feign/api.mustache +++ b/modules/swagger-codegen/src/main/resources/Java/libraries/feign/api.mustache @@ -26,7 +26,7 @@ public interface {{classname}} extends ApiClient.Api { "{{paramName}}: {{=<% %>=}}{<%paramName%>}<%={{ }}=%>"{{#hasMore}}, {{/hasMore}}{{/headerParams}} }) - {{#returnType}}{{{returnType}}} {{/returnType}}{{^returnType}}void {{/returnType}}{{nickname}}({{#allParams}}{{^vendorExtensions.x-isBody}}@Param("{{paramName}}") {{/vendorExtensions.x-isBody}}{{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}); + {{#returnType}}{{{returnType}}} {{/returnType}}{{^returnType}}void {{/returnType}}{{nickname}}({{#allParams}}{{^isBodyParam}}@Param("{{paramName}}") {{/isBodyParam}}{{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}); {{/operation}} {{/operations}} } diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/ApiClient.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/ApiClient.java index 001d05f49f05..42439dbdf24c 100644 --- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/ApiClient.java +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/ApiClient.java @@ -8,7 +8,7 @@ import feign.jackson.JacksonDecoder; import feign.jackson.JacksonEncoder; import feign.slf4j.Slf4jLogger; -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T22:27:06.680-05:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-09T22:59:22.180-05:00") public class ApiClient { public interface Api {} diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/FormAwareEncoder.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/FormAwareEncoder.java index 3f0230a406a8..e38faaf009a2 100644 --- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/FormAwareEncoder.java +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/FormAwareEncoder.java @@ -14,7 +14,7 @@ import feign.codec.EncodeException; import feign.codec.Encoder; import feign.RequestTemplate; -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T22:27:06.680-05:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-09T22:59:22.180-05:00") public class FormAwareEncoder implements Encoder { public static final String UTF_8 = "utf-8"; private static final String LINE_FEED = "\r\n"; diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/StringUtil.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/StringUtil.java index db6460490faa..cc437fee0c00 100644 --- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/StringUtil.java +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/StringUtil.java @@ -1,6 +1,6 @@ package io.swagger.client; -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T22:27:06.680-05:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-09T22:59:22.180-05:00") public class StringUtil { /** * Check if the given array contains the given value (with case-insensitive comparison). diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/PetApi.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/PetApi.java index caa70b4260af..536e953e699a 100644 --- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/PetApi.java +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/PetApi.java @@ -11,7 +11,7 @@ import java.util.*; import feign.*; -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T22:27:06.680-05:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-09T22:59:22.180-05:00") public interface PetApi extends ApiClient.Api { diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/StoreApi.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/StoreApi.java index a022f684a4e2..552c62db9193 100644 --- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/StoreApi.java +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/StoreApi.java @@ -10,7 +10,7 @@ import java.util.*; import feign.*; -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T22:27:06.680-05:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-09T22:59:22.180-05:00") public interface StoreApi extends ApiClient.Api { diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/UserApi.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/UserApi.java index b2bac15d873f..610bd3997001 100644 --- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/UserApi.java +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/UserApi.java @@ -10,7 +10,7 @@ import java.util.*; import feign.*; -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T22:27:06.680-05:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-09T22:59:22.180-05:00") public interface UserApi extends ApiClient.Api { diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/ApiResponse.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/ApiResponse.java index 4843a51e9880..ab98bf61e891 100644 --- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/ApiResponse.java +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/ApiResponse.java @@ -12,7 +12,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; @ApiModel(description = "") -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T22:27:06.680-05:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-09T22:59:22.180-05:00") public class ApiResponse { private Integer code = null; diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Category.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Category.java index a414345dd637..3a22c2b9c604 100644 --- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Category.java +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Category.java @@ -12,7 +12,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; @ApiModel(description = "") -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T22:27:06.680-05:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-09T22:59:22.180-05:00") public class Category { private Long id = null; diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Order.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Order.java index 4f045ca04101..9b87b66c9e6a 100644 --- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Order.java +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Order.java @@ -13,7 +13,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; @ApiModel(description = "") -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T22:27:06.680-05:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-09T22:59:22.180-05:00") public class Order { private Long id = null; diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Pet.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Pet.java index 4029fc4362ef..07c18075bd2c 100644 --- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Pet.java +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Pet.java @@ -15,7 +15,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; @ApiModel(description = "") -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T22:27:06.680-05:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-09T22:59:22.180-05:00") public class Pet { private Long id = null; diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Tag.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Tag.java index 2c3b0132bc6b..80b3919e5325 100644 --- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Tag.java +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Tag.java @@ -12,7 +12,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; @ApiModel(description = "") -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T22:27:06.680-05:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-09T22:59:22.180-05:00") public class Tag { private Long id = null; diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/User.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/User.java index a8e902dd21ff..efa18d38dcf8 100644 --- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/User.java +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/User.java @@ -12,7 +12,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; @ApiModel(description = "") -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-07T22:27:06.680-05:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-09T22:59:22.180-05:00") public class User { private Long id = null; From 75a1f97a1e116dd47758266e8465be4bc8184d33 Mon Sep 17 00:00:00 2001 From: wing328 Date: Thu, 10 Dec 2015 15:21:52 +0800 Subject: [PATCH 33/71] minor style change for objc client --- .../resources/objc/ApiClient-body.mustache | 43 +++++++------- .../src/main/resources/objc/api-body.mustache | 6 +- .../main/resources/objc/model-body.mustache | 5 +- .../objc/SwaggerClient/SWGApiClient.m | 59 ++++++++++--------- .../petstore/objc/SwaggerClient/SWGCategory.m | 5 +- .../petstore/objc/SwaggerClient/SWGOrder.m | 5 +- .../petstore/objc/SwaggerClient/SWGPet.m | 5 +- .../petstore/objc/SwaggerClient/SWGPetApi.m | 6 +- .../petstore/objc/SwaggerClient/SWGTag.m | 5 +- .../petstore/objc/SwaggerClient/SWGUser.m | 5 +- .../petstore/objc/SwaggerClient/SWGUserApi.m | 4 +- 11 files changed, 79 insertions(+), 69 deletions(-) diff --git a/modules/swagger-codegen/src/main/resources/objc/ApiClient-body.mustache b/modules/swagger-codegen/src/main/resources/objc/ApiClient-body.mustache index 0c23c8004694..25b5d9adfbff 100644 --- a/modules/swagger-codegen/src/main/resources/objc/ApiClient-body.mustache +++ b/modules/swagger-codegen/src/main/resources/objc/ApiClient-body.mustache @@ -132,17 +132,20 @@ static void (^reachabilityChangeBlock)(int); if (accepts == nil || [accepts count] == 0) { return @""; } + NSMutableArray *lowerAccepts = [[NSMutableArray alloc] initWithCapacity:[accepts count]]; for (NSString *string in accepts) { NSString * lowerAccept = [string lowercaseString]; - if([lowerAccept containsString:@"application/json"]) { + if ([lowerAccept containsString:@"application/json"]) { return @"application/json"; } [lowerAccepts addObject:lowerAccept]; } - if(lowerAccepts.count == 1){ + + if (lowerAccepts.count == 1) { return [lowerAccepts firstObject]; } + return [lowerAccepts componentsJoinedByString:@", "]; } @@ -169,7 +172,7 @@ static void (^reachabilityChangeBlock)(int); } + (NSString*)escape:(id)unescaped { - if([unescaped isKindOfClass:[NSString class]]){ + if ([unescaped isKindOfClass:[NSString class]]){ return (NSString *)CFBridgingRelease (CFURLCreateStringByAddingPercentEscapes( NULL, @@ -210,7 +213,7 @@ static void (^reachabilityChangeBlock)(int); -(Boolean) executeRequestWithId:(NSNumber*) requestId { NSSet* matchingItems = [queuedRequests objectsPassingTest:^BOOL(id obj, BOOL *stop) { - if([obj intValue] == [requestId intValue]) { + if ([obj intValue] == [requestId intValue]) { return YES; } else { @@ -218,7 +221,7 @@ static void (^reachabilityChangeBlock)(int); } }]; - if(matchingItems.count == 1) { + if (matchingItems.count == 1) { {{classPrefix}}DebugLog(@"removed request id %@", requestId); [queuedRequests removeObject:requestId]; return YES; @@ -266,7 +269,7 @@ static void (^reachabilityChangeBlock)(int); } // call the reachability block, if configured - if(reachabilityChangeBlock != nil) { + if (reachabilityChangeBlock != nil) { reachabilityChangeBlock(status); } }]; @@ -408,16 +411,16 @@ static void (^reachabilityChangeBlock)(int); completionBlock: (void (^)(id, NSError *))completionBlock { AFHTTPRequestOperation *op = [self HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id response) { - if([self executeRequestWithId:requestId]) { + if ([self executeRequestWithId:requestId]) { [self logResponse:operation forRequest:request error:nil]; NSDictionary *responseHeaders = [[operation response] allHeaderFields]; self.HTTPResponseHeaders = responseHeaders; completionBlock(response, nil); } } failure:^(AFHTTPRequestOperation *operation, NSError *error) { - if([self executeRequestWithId:requestId]) { + if ([self executeRequestWithId:requestId]) { NSMutableDictionary *userInfo = [error.userInfo mutableCopy]; - if(operation.responseObject) { + if (operation.responseObject) { // Add in the (parsed) response body. userInfo[{{classPrefix}}ResponseObjectErrorKey] = operation.responseObject; } @@ -588,10 +591,10 @@ static void (^reachabilityChangeBlock)(int); // request cache BOOL hasHeaderParams = false; - if(headerParams != nil && [headerParams count] > 0) { + if (headerParams != nil && [headerParams count] > 0) { hasHeaderParams = true; } - if(offlineState) { + if (offlineState) { {{classPrefix}}DebugLog(@"%@ cache forced", resourcePath); [request setCachePolicy:NSURLRequestReturnCacheDataDontLoad]; } @@ -604,7 +607,7 @@ static void (^reachabilityChangeBlock)(int); [request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData]; } - if(hasHeaderParams){ + if (hasHeaderParams){ for(NSString * key in [headerParams keyEnumerator]){ [request setValue:[headerParams valueForKey:key] forHTTPHeaderField:key]; } @@ -637,36 +640,36 @@ static void (^reachabilityChangeBlock)(int); int counter = 0; NSMutableString * requestUrl = [NSMutableString stringWithFormat:@"%@", path]; - if(queryParams != nil){ + if (queryParams != nil){ for(NSString * key in [queryParams keyEnumerator]){ - if(counter == 0) separator = @"?"; + if (counter == 0) separator = @"?"; else separator = @"&"; id queryParam = [queryParams valueForKey:key]; - if([queryParam isKindOfClass:[NSString class]]){ + if ([queryParam isKindOfClass:[NSString class]]){ [requestUrl appendString:[NSString stringWithFormat:@"%@%@=%@", separator, [{{classPrefix}}ApiClient escape:key], [{{classPrefix}}ApiClient escape:[queryParams valueForKey:key]]]]; } - else if([queryParam isKindOfClass:[{{classPrefix}}QueryParamCollection class]]){ + else if ([queryParam isKindOfClass:[{{classPrefix}}QueryParamCollection class]]){ {{classPrefix}}QueryParamCollection * coll = ({{classPrefix}}QueryParamCollection*) queryParam; NSArray* values = [coll values]; NSString* format = [coll format]; - if([format isEqualToString:@"csv"]) { + if ([format isEqualToString:@"csv"]) { [requestUrl appendString:[NSString stringWithFormat:@"%@%@=%@", separator, [{{classPrefix}}ApiClient escape:key], [NSString stringWithFormat:@"%@", [values componentsJoinedByString:@","]]]]; } - else if([format isEqualToString:@"tsv"]) { + else if ([format isEqualToString:@"tsv"]) { [requestUrl appendString:[NSString stringWithFormat:@"%@%@=%@", separator, [{{classPrefix}}ApiClient escape:key], [NSString stringWithFormat:@"%@", [values componentsJoinedByString:@"\t"]]]]; } - else if([format isEqualToString:@"pipes"]) { + else if ([format isEqualToString:@"pipes"]) { [requestUrl appendString:[NSString stringWithFormat:@"%@%@=%@", separator, [{{classPrefix}}ApiClient escape:key], [NSString stringWithFormat:@"%@", [values componentsJoinedByString:@"|"]]]]; } - else if([format isEqualToString:@"multi"]) { + else if ([format isEqualToString:@"multi"]) { for(id obj in values) { [requestUrl appendString:[NSString stringWithFormat:@"%@%@=%@", separator, [{{classPrefix}}ApiClient escape:key], [NSString stringWithFormat:@"%@", obj]]]; diff --git a/modules/swagger-codegen/src/main/resources/objc/api-body.mustache b/modules/swagger-codegen/src/main/resources/objc/api-body.mustache index 60358e4e9da8..d84e350360f5 100644 --- a/modules/swagger-codegen/src/main/resources/objc/api-body.mustache +++ b/modules/swagger-codegen/src/main/resources/objc/api-body.mustache @@ -105,7 +105,7 @@ static {{classname}}* singletonAPI = nil; {{/pathParams}} NSMutableDictionary* queryParams = [[NSMutableDictionary alloc] init]; - {{#queryParams}}if({{paramName}} != nil) { + {{#queryParams}}if ({{paramName}} != nil) { {{#collectionFormat}} queryParams[@"{{baseName}}"] = [[{{classPrefix}}QueryParamCollection alloc] initWithValuesAndFormat: {{baseName}} format: @"{{collectionFormat}}"]; {{/collectionFormat}} @@ -114,7 +114,7 @@ static {{classname}}* singletonAPI = nil; {{/queryParams}} NSMutableDictionary* headerParams = [NSMutableDictionary dictionaryWithDictionary:self.defaultHeaders]; - {{#headerParams}}if({{paramName}} != nil) { + {{#headerParams}}if ({{paramName}} != nil) { headerParams[@"{{baseName}}"] = {{paramName}}; } {{/headerParams}} @@ -159,7 +159,7 @@ static {{classname}}* singletonAPI = nil; {{#requiredParamCount}} {{#requiredParams}} - if({{paramName}} == nil) { + if ({{paramName}} == nil) { // error } {{/requiredParams}} diff --git a/modules/swagger-codegen/src/main/resources/objc/model-body.mustache b/modules/swagger-codegen/src/main/resources/objc/model-body.mustache index ba76b12aeb89..3d70cebfae20 100644 --- a/modules/swagger-codegen/src/main/resources/objc/model-body.mustache +++ b/modules/swagger-codegen/src/main/resources/objc/model-body.mustache @@ -6,12 +6,13 @@ - (instancetype)init { self = [super init]; - if (self) - { + + if (self) { // initalise property's default value, if any {{#vars}}{{#defaultValue}}self.{{name}} = {{{defaultValue}}}; {{/defaultValue}}{{/vars}} } + return self; } diff --git a/samples/client/petstore/objc/SwaggerClient/SWGApiClient.m b/samples/client/petstore/objc/SwaggerClient/SWGApiClient.m index dcd33575fc6f..4dce6d2fa8bc 100644 --- a/samples/client/petstore/objc/SwaggerClient/SWGApiClient.m +++ b/samples/client/petstore/objc/SwaggerClient/SWGApiClient.m @@ -128,24 +128,25 @@ static void (^reachabilityChangeBlock)(int); /* * Detect `Accept` from accepts */ -+ (NSString *) selectHeaderAccept:(NSArray *)accepts -{ ++ (NSString *) selectHeaderAccept:(NSArray *)accepts { if (accepts == nil || [accepts count] == 0) { return @""; } NSMutableArray *lowerAccepts = [[NSMutableArray alloc] initWithCapacity:[accepts count]]; - [accepts enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { - [lowerAccepts addObject:[obj lowercaseString]]; - }]; - - - if ([lowerAccepts containsObject:@"application/json"]) { - return @"application/json"; + for (NSString *string in accepts) { + NSString * lowerAccept = [string lowercaseString]; + if ([lowerAccept containsString:@"application/json"]) { + return @"application/json"; + } + [lowerAccepts addObject:lowerAccept]; } - else { - return [lowerAccepts componentsJoinedByString:@", "]; + + if (lowerAccepts.count == 1) { + return [lowerAccepts firstObject]; } + + return [lowerAccepts componentsJoinedByString:@", "]; } /* @@ -171,7 +172,7 @@ static void (^reachabilityChangeBlock)(int); } + (NSString*)escape:(id)unescaped { - if([unescaped isKindOfClass:[NSString class]]){ + if ([unescaped isKindOfClass:[NSString class]]){ return (NSString *)CFBridgingRelease (CFURLCreateStringByAddingPercentEscapes( NULL, @@ -212,7 +213,7 @@ static void (^reachabilityChangeBlock)(int); -(Boolean) executeRequestWithId:(NSNumber*) requestId { NSSet* matchingItems = [queuedRequests objectsPassingTest:^BOOL(id obj, BOOL *stop) { - if([obj intValue] == [requestId intValue]) { + if ([obj intValue] == [requestId intValue]) { return YES; } else { @@ -220,7 +221,7 @@ static void (^reachabilityChangeBlock)(int); } }]; - if(matchingItems.count == 1) { + if (matchingItems.count == 1) { SWGDebugLog(@"removed request id %@", requestId); [queuedRequests removeObject:requestId]; return YES; @@ -268,7 +269,7 @@ static void (^reachabilityChangeBlock)(int); } // call the reachability block, if configured - if(reachabilityChangeBlock != nil) { + if (reachabilityChangeBlock != nil) { reachabilityChangeBlock(status); } }]; @@ -410,16 +411,16 @@ static void (^reachabilityChangeBlock)(int); completionBlock: (void (^)(id, NSError *))completionBlock { AFHTTPRequestOperation *op = [self HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id response) { - if([self executeRequestWithId:requestId]) { + if ([self executeRequestWithId:requestId]) { [self logResponse:operation forRequest:request error:nil]; NSDictionary *responseHeaders = [[operation response] allHeaderFields]; self.HTTPResponseHeaders = responseHeaders; completionBlock(response, nil); } } failure:^(AFHTTPRequestOperation *operation, NSError *error) { - if([self executeRequestWithId:requestId]) { + if ([self executeRequestWithId:requestId]) { NSMutableDictionary *userInfo = [error.userInfo mutableCopy]; - if(operation.responseObject) { + if (operation.responseObject) { // Add in the (parsed) response body. userInfo[SWGResponseObjectErrorKey] = operation.responseObject; } @@ -590,10 +591,10 @@ static void (^reachabilityChangeBlock)(int); // request cache BOOL hasHeaderParams = false; - if(headerParams != nil && [headerParams count] > 0) { + if (headerParams != nil && [headerParams count] > 0) { hasHeaderParams = true; } - if(offlineState) { + if (offlineState) { SWGDebugLog(@"%@ cache forced", resourcePath); [request setCachePolicy:NSURLRequestReturnCacheDataDontLoad]; } @@ -606,7 +607,7 @@ static void (^reachabilityChangeBlock)(int); [request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData]; } - if(hasHeaderParams){ + if (hasHeaderParams){ for(NSString * key in [headerParams keyEnumerator]){ [request setValue:[headerParams valueForKey:key] forHTTPHeaderField:key]; } @@ -639,36 +640,36 @@ static void (^reachabilityChangeBlock)(int); int counter = 0; NSMutableString * requestUrl = [NSMutableString stringWithFormat:@"%@", path]; - if(queryParams != nil){ + if (queryParams != nil){ for(NSString * key in [queryParams keyEnumerator]){ - if(counter == 0) separator = @"?"; + if (counter == 0) separator = @"?"; else separator = @"&"; id queryParam = [queryParams valueForKey:key]; - if([queryParam isKindOfClass:[NSString class]]){ + if ([queryParam isKindOfClass:[NSString class]]){ [requestUrl appendString:[NSString stringWithFormat:@"%@%@=%@", separator, [SWGApiClient escape:key], [SWGApiClient escape:[queryParams valueForKey:key]]]]; } - else if([queryParam isKindOfClass:[SWGQueryParamCollection class]]){ + else if ([queryParam isKindOfClass:[SWGQueryParamCollection class]]){ SWGQueryParamCollection * coll = (SWGQueryParamCollection*) queryParam; NSArray* values = [coll values]; NSString* format = [coll format]; - if([format isEqualToString:@"csv"]) { + if ([format isEqualToString:@"csv"]) { [requestUrl appendString:[NSString stringWithFormat:@"%@%@=%@", separator, [SWGApiClient escape:key], [NSString stringWithFormat:@"%@", [values componentsJoinedByString:@","]]]]; } - else if([format isEqualToString:@"tsv"]) { + else if ([format isEqualToString:@"tsv"]) { [requestUrl appendString:[NSString stringWithFormat:@"%@%@=%@", separator, [SWGApiClient escape:key], [NSString stringWithFormat:@"%@", [values componentsJoinedByString:@"\t"]]]]; } - else if([format isEqualToString:@"pipes"]) { + else if ([format isEqualToString:@"pipes"]) { [requestUrl appendString:[NSString stringWithFormat:@"%@%@=%@", separator, [SWGApiClient escape:key], [NSString stringWithFormat:@"%@", [values componentsJoinedByString:@"|"]]]]; } - else if([format isEqualToString:@"multi"]) { + else if ([format isEqualToString:@"multi"]) { for(id obj in values) { [requestUrl appendString:[NSString stringWithFormat:@"%@%@=%@", separator, [SWGApiClient escape:key], [NSString stringWithFormat:@"%@", obj]]]; diff --git a/samples/client/petstore/objc/SwaggerClient/SWGCategory.m b/samples/client/petstore/objc/SwaggerClient/SWGCategory.m index 7c71e4af0f45..0d10e25426ea 100644 --- a/samples/client/petstore/objc/SwaggerClient/SWGCategory.m +++ b/samples/client/petstore/objc/SwaggerClient/SWGCategory.m @@ -4,11 +4,12 @@ - (instancetype)init { self = [super init]; - if (self) - { + + if (self) { // initalise property's default value, if any } + return self; } diff --git a/samples/client/petstore/objc/SwaggerClient/SWGOrder.m b/samples/client/petstore/objc/SwaggerClient/SWGOrder.m index ba0b637eb09a..abf77a7b399d 100644 --- a/samples/client/petstore/objc/SwaggerClient/SWGOrder.m +++ b/samples/client/petstore/objc/SwaggerClient/SWGOrder.m @@ -4,11 +4,12 @@ - (instancetype)init { self = [super init]; - if (self) - { + + if (self) { // initalise property's default value, if any } + return self; } diff --git a/samples/client/petstore/objc/SwaggerClient/SWGPet.m b/samples/client/petstore/objc/SwaggerClient/SWGPet.m index 388157eb0cc6..f4fd77ea33f0 100644 --- a/samples/client/petstore/objc/SwaggerClient/SWGPet.m +++ b/samples/client/petstore/objc/SwaggerClient/SWGPet.m @@ -4,11 +4,12 @@ - (instancetype)init { self = [super init]; - if (self) - { + + if (self) { // initalise property's default value, if any } + return self; } diff --git a/samples/client/petstore/objc/SwaggerClient/SWGPetApi.m b/samples/client/petstore/objc/SwaggerClient/SWGPetApi.m index bff6c3765b1e..c7c2ed175c6f 100644 --- a/samples/client/petstore/objc/SwaggerClient/SWGPetApi.m +++ b/samples/client/petstore/objc/SwaggerClient/SWGPetApi.m @@ -250,7 +250,7 @@ static SWGPetApi* singletonAPI = nil; NSMutableDictionary* queryParams = [[NSMutableDictionary alloc] init]; - if(status != nil) { + if (status != nil) { queryParams[@"status"] = [[SWGQueryParamCollection alloc] initWithValuesAndFormat: status format: @"multi"]; @@ -334,7 +334,7 @@ static SWGPetApi* singletonAPI = nil; NSMutableDictionary* queryParams = [[NSMutableDictionary alloc] init]; - if(tags != nil) { + if (tags != nil) { queryParams[@"tags"] = [[SWGQueryParamCollection alloc] initWithValuesAndFormat: tags format: @"multi"]; @@ -622,7 +622,7 @@ static SWGPetApi* singletonAPI = nil; NSMutableDictionary* headerParams = [NSMutableDictionary dictionaryWithDictionary:self.defaultHeaders]; - if(apiKey != nil) { + if (apiKey != nil) { headerParams[@"api_key"] = apiKey; } diff --git a/samples/client/petstore/objc/SwaggerClient/SWGTag.m b/samples/client/petstore/objc/SwaggerClient/SWGTag.m index 7a7e7550debb..b19085e2e6b5 100644 --- a/samples/client/petstore/objc/SwaggerClient/SWGTag.m +++ b/samples/client/petstore/objc/SwaggerClient/SWGTag.m @@ -4,11 +4,12 @@ - (instancetype)init { self = [super init]; - if (self) - { + + if (self) { // initalise property's default value, if any } + return self; } diff --git a/samples/client/petstore/objc/SwaggerClient/SWGUser.m b/samples/client/petstore/objc/SwaggerClient/SWGUser.m index bdb26cf36a62..ac059240e7fe 100644 --- a/samples/client/petstore/objc/SwaggerClient/SWGUser.m +++ b/samples/client/petstore/objc/SwaggerClient/SWGUser.m @@ -4,11 +4,12 @@ - (instancetype)init { self = [super init]; - if (self) - { + + if (self) { // initalise property's default value, if any } + return self; } diff --git a/samples/client/petstore/objc/SwaggerClient/SWGUserApi.m b/samples/client/petstore/objc/SwaggerClient/SWGUserApi.m index 75cf8d51b0ea..faf0f928baf5 100644 --- a/samples/client/petstore/objc/SwaggerClient/SWGUserApi.m +++ b/samples/client/petstore/objc/SwaggerClient/SWGUserApi.m @@ -331,11 +331,11 @@ static SWGUserApi* singletonAPI = nil; NSMutableDictionary* queryParams = [[NSMutableDictionary alloc] init]; - if(username != nil) { + if (username != nil) { queryParams[@"username"] = username; } - if(password != nil) { + if (password != nil) { queryParams[@"password"] = password; } From e9ef143d8f4120664e7c009bbccd79d44b372cc2 Mon Sep 17 00:00:00 2001 From: xhh Date: Thu, 10 Dec 2015 15:25:07 +0800 Subject: [PATCH 34/71] Ruby client: allow setting Configuration in ApiClient Removed the singleton design from the Configuration class. Added a `config` field to ApiClient to hold the settings the ApiClient uses. --- .../src/main/resources/ruby/api.mustache | 12 ++-- .../main/resources/ruby/api_client.mustache | 43 ++++++------ .../resources/ruby/configuration.mustache | 29 +++----- .../src/main/resources/ruby/gem.mustache | 16 ++--- samples/client/petstore/ruby/lib/petstore.rb | 16 ++--- .../petstore/ruby/lib/petstore/api/pet_api.rb | 68 +++++++++---------- .../ruby/lib/petstore/api/store_api.rb | 36 +++++----- .../ruby/lib/petstore/api/user_api.rb | 68 +++++++++---------- .../petstore/ruby/lib/petstore/api_client.rb | 43 ++++++------ .../ruby/lib/petstore/configuration.rb | 29 +++----- .../petstore/ruby/spec/api_client_spec.rb | 27 ++++++-- .../petstore/ruby/spec/configuration_spec.rb | 2 +- .../client/petstore/ruby/spec/spec_helper.rb | 2 +- 13 files changed, 194 insertions(+), 197 deletions(-) diff --git a/modules/swagger-codegen/src/main/resources/ruby/api.mustache b/modules/swagger-codegen/src/main/resources/ruby/api.mustache index 65e00081686e..d7967135336d 100644 --- a/modules/swagger-codegen/src/main/resources/ruby/api.mustache +++ b/modules/swagger-codegen/src/main/resources/ruby/api.mustache @@ -5,8 +5,8 @@ module {{moduleName}} class {{classname}} attr_accessor :api_client - def initialize(api_client = nil) - @api_client = api_client || Configuration.api_client + def initialize(api_client = ApiClient.default) + @api_client = api_client end {{#operation}} {{newline}} @@ -28,8 +28,8 @@ module {{moduleName}} {{#allParams}}{{^required}} # @option opts [{{{dataType}}}] :{{paramName}} {{description}} {{/required}}{{/allParams}} # @return [Array<({{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}nil{{/returnType}}, Fixnum, Hash)>] {{#returnType}}{{{returnType}}} data{{/returnType}}{{^returnType}}nil{{/returnType}}, response status code and response headers def {{operationId}}_with_http_info({{#allParams}}{{#required}}{{paramName}}, {{/required}}{{/allParams}}opts = {}) - if Configuration.debugging - Configuration.logger.debug "Calling API: {{classname}}#{{operationId}} ..." + if @api_client.config.debugging + @api_client.config.logger.debug "Calling API: {{classname}}#{{operationId}} ..." end {{#allParams}}{{#required}} # verify the required parameter '{{paramName}}' is set @@ -81,8 +81,8 @@ module {{moduleName}} :body => post_body, :auth_names => auth_names{{#returnType}}, :return_type => '{{{returnType}}}'{{/returnType}}) - if Configuration.debugging - Configuration.logger.debug "API called: {{classname}}#{{operationId}}\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" + if @api_client.config.debugging + @api_client.config.logger.debug "API called: {{classname}}#{{operationId}}\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" end return data, status_code, headers end diff --git a/modules/swagger-codegen/src/main/resources/ruby/api_client.mustache b/modules/swagger-codegen/src/main/resources/ruby/api_client.mustache index fa14e2f88ca4..837b1234fd0b 100644 --- a/modules/swagger-codegen/src/main/resources/ruby/api_client.mustache +++ b/modules/swagger-codegen/src/main/resources/ruby/api_client.mustache @@ -7,24 +7,27 @@ require 'uri' module {{moduleName}} class ApiClient - - attr_accessor :host + # The Configuration object holding settings to be used in the API client. + attr_accessor :config # Defines the headers to be used in HTTP requests of all API calls by default. # # @return [Hash] attr_accessor :default_headers - def initialize(host = nil) - @host = host || Configuration.base_url - @format = 'json' + def initialize(config = Configuration.default) + @config = config @user_agent = "ruby-swagger-#{VERSION}" @default_headers = { - 'Content-Type' => "application/#{@format.downcase}", + 'Content-Type' => "application/json", 'User-Agent' => @user_agent } end + def self.default + @@default ||= ApiClient.new + end + # Call an API with given options. # # @return [Array<(Object, Fixnum, Hash)>] an array of 3 elements: @@ -33,8 +36,8 @@ module {{moduleName}} request = build_request(http_method, path, opts) response = request.run - if Configuration.debugging - Configuration.logger.debug "HTTP response body ~BEGIN~\n#{response.body}\n~END~\n" + if @config.debugging + @config.logger.debug "HTTP response body ~BEGIN~\n#{response.body}\n~END~\n" end unless response.success? @@ -68,18 +71,18 @@ module {{moduleName}} :method => http_method, :headers => header_params, :params => query_params, - :ssl_verifypeer => Configuration.verify_ssl, - :sslcert => Configuration.cert_file, - :sslkey => Configuration.key_file, - :cainfo => Configuration.ssl_ca_cert, - :verbose => Configuration.debugging + :ssl_verifypeer => @config.verify_ssl, + :sslcert => @config.cert_file, + :sslkey => @config.key_file, + :cainfo => @config.ssl_ca_cert, + :verbose => @config.debugging } if [:post, :patch, :put, :delete].include?(http_method) req_body = build_request_body(header_params, form_params, opts[:body]) req_opts.update :body => req_body - if Configuration.debugging - Configuration.logger.debug "HTTP request body param ~BEGIN~\n#{req_body}\n~END~\n" + if @config.debugging + @config.logger.debug "HTTP request body param ~BEGIN~\n#{req_body}\n~END~\n" end end @@ -168,7 +171,7 @@ module {{moduleName}} # @see Configuration#temp_folder_path # @return [File] the file downloaded def download_file(response) - tmp_file = Tempfile.new '', Configuration.temp_folder_path + tmp_file = Tempfile.new '', @config.temp_folder_path content_disposition = response.headers['Content-Disposition'] if content_disposition filename = content_disposition[/filename=['"]?([^'"\s]+)['"]?/, 1] @@ -180,15 +183,15 @@ module {{moduleName}} tmp_file.close! File.open(path, 'w') { |file| file.write(response.body) } - Configuration.logger.info "File written to #{path}. Please move the file to a proper "\ - "folder for further processing and delete the temp afterwards" + @config.logger.info "File written to #{path}. Please move the file to a proper folder "\ + "for further processing and delete the temp afterwards" File.new(path) end def build_request_url(path) # Add leading and trailing slashes to path path = "/#{path}".gsub(/\/+/, '/') - URI.encode(host + path) + URI.encode(@config.base_url + path) end def build_request_body(header_params, form_params, body) @@ -216,7 +219,7 @@ module {{moduleName}} # Update hearder and query params based on authentication settings. def update_params_for_auth!(header_params, query_params, auth_names) Array(auth_names).each do |auth_name| - auth_setting = Configuration.auth_settings[auth_name] + auth_setting = @config.auth_settings[auth_name] next unless auth_setting case auth_setting[:in] when 'header' then header_params[auth_setting[:key]] = auth_setting[:value] diff --git a/modules/swagger-codegen/src/main/resources/ruby/configuration.mustache b/modules/swagger-codegen/src/main/resources/ruby/configuration.mustache index 89bf133b22c1..4c05f2560fa1 100644 --- a/modules/swagger-codegen/src/main/resources/ruby/configuration.mustache +++ b/modules/swagger-codegen/src/main/resources/ruby/configuration.mustache @@ -1,14 +1,7 @@ require 'uri' -require 'singleton' module {{moduleName}} class Configuration - - include Singleton - - # Default api client - attr_accessor :api_client - # Defines url scheme attr_accessor :scheme @@ -94,17 +87,6 @@ module {{moduleName}} attr_accessor :force_ending_format - class << self - def method_missing(method_name, *args, &block) - config = Configuration.instance - if config.respond_to?(method_name) - config.send(method_name, *args, &block) - else - super - end - end - end - def initialize @scheme = '{{scheme}}' @host = '{{host}}' @@ -118,10 +100,17 @@ module {{moduleName}} @inject_format = false @force_ending_format = false @logger = defined?(Rails) ? Rails.logger : Logger.new(STDOUT) + + yield(self) if block_given? end - def api_client - @api_client ||= ApiClient.new + # The default Configuration object. + def self.default + @@default ||= Configuration.new + end + + def configure + yield(self) if block_given? end def scheme=(scheme) diff --git a/modules/swagger-codegen/src/main/resources/ruby/gem.mustache b/modules/swagger-codegen/src/main/resources/ruby/gem.mustache index eb0b8cfbf0f9..2000b2be86f1 100644 --- a/modules/swagger-codegen/src/main/resources/ruby/gem.mustache +++ b/modules/swagger-codegen/src/main/resources/ruby/gem.mustache @@ -19,17 +19,17 @@ require '{{importPath}}' module {{moduleName}} class << self - # Configure sdk using block. - # {{moduleName}}.configure do |config| - # config.username = "xxx" - # config.password = "xxx" - # end - # If no block given, return the configuration singleton instance. + # Customize default settings for the SDK using block. + # {{moduleName}}.configure do |config| + # config.username = "xxx" + # config.password = "xxx" + # end + # If no block given, return the default Configuration object. def configure if block_given? - yield Configuration.instance + yield(Configuration.default) else - Configuration.instance + Configuration.default end end end diff --git a/samples/client/petstore/ruby/lib/petstore.rb b/samples/client/petstore/ruby/lib/petstore.rb index c13e99f29fc4..4c21fb331d3f 100644 --- a/samples/client/petstore/ruby/lib/petstore.rb +++ b/samples/client/petstore/ruby/lib/petstore.rb @@ -19,17 +19,17 @@ require 'petstore/api/pet_api' module Petstore class << self - # Configure sdk using block. - # Petstore.configure do |config| - # config.username = "xxx" - # config.password = "xxx" - # end - # If no block given, return the configuration singleton instance. + # Customize default settings for the SDK using block. + # Petstore.configure do |config| + # config.username = "xxx" + # config.password = "xxx" + # end + # If no block given, return the default Configuration object. def configure if block_given? - yield Configuration.instance + yield(Configuration.default) else - Configuration.instance + Configuration.default end end end diff --git a/samples/client/petstore/ruby/lib/petstore/api/pet_api.rb b/samples/client/petstore/ruby/lib/petstore/api/pet_api.rb index acbd564db530..9641ad0b7079 100644 --- a/samples/client/petstore/ruby/lib/petstore/api/pet_api.rb +++ b/samples/client/petstore/ruby/lib/petstore/api/pet_api.rb @@ -4,8 +4,8 @@ module Petstore class PetApi attr_accessor :api_client - def initialize(api_client = nil) - @api_client = api_client || Configuration.api_client + def initialize(api_client = ApiClient.default) + @api_client = api_client end # Update an existing pet @@ -24,8 +24,8 @@ module Petstore # @option opts [Pet] :body Pet object that needs to be added to the store # @return [Array<(nil, Fixnum, Hash)>] nil, response status code and response headers def update_pet_with_http_info(opts = {}) - if Configuration.debugging - Configuration.logger.debug "Calling API: PetApi#update_pet ..." + if @api_client.config.debugging + @api_client.config.logger.debug "Calling API: PetApi#update_pet ..." end # resource path @@ -59,8 +59,8 @@ module Petstore :form_params => form_params, :body => post_body, :auth_names => auth_names) - if Configuration.debugging - Configuration.logger.debug "API called: PetApi#update_pet\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" + if @api_client.config.debugging + @api_client.config.logger.debug "API called: PetApi#update_pet\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" end return data, status_code, headers end @@ -81,8 +81,8 @@ module Petstore # @option opts [Pet] :body Pet object that needs to be added to the store # @return [Array<(nil, Fixnum, Hash)>] nil, response status code and response headers def add_pet_with_http_info(opts = {}) - if Configuration.debugging - Configuration.logger.debug "Calling API: PetApi#add_pet ..." + if @api_client.config.debugging + @api_client.config.logger.debug "Calling API: PetApi#add_pet ..." end # resource path @@ -116,8 +116,8 @@ module Petstore :form_params => form_params, :body => post_body, :auth_names => auth_names) - if Configuration.debugging - Configuration.logger.debug "API called: PetApi#add_pet\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" + if @api_client.config.debugging + @api_client.config.logger.debug "API called: PetApi#add_pet\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" end return data, status_code, headers end @@ -138,8 +138,8 @@ module Petstore # @option opts [Array] :status Status values that need to be considered for filter # @return [Array<(Array, Fixnum, Hash)>] Array data, response status code and response headers def find_pets_by_status_with_http_info(opts = {}) - if Configuration.debugging - Configuration.logger.debug "Calling API: PetApi#find_pets_by_status ..." + if @api_client.config.debugging + @api_client.config.logger.debug "Calling API: PetApi#find_pets_by_status ..." end # resource path @@ -175,8 +175,8 @@ module Petstore :body => post_body, :auth_names => auth_names, :return_type => 'Array') - if Configuration.debugging - Configuration.logger.debug "API called: PetApi#find_pets_by_status\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" + if @api_client.config.debugging + @api_client.config.logger.debug "API called: PetApi#find_pets_by_status\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" end return data, status_code, headers end @@ -197,8 +197,8 @@ module Petstore # @option opts [Array] :tags Tags to filter by # @return [Array<(Array, Fixnum, Hash)>] Array data, response status code and response headers def find_pets_by_tags_with_http_info(opts = {}) - if Configuration.debugging - Configuration.logger.debug "Calling API: PetApi#find_pets_by_tags ..." + if @api_client.config.debugging + @api_client.config.logger.debug "Calling API: PetApi#find_pets_by_tags ..." end # resource path @@ -234,8 +234,8 @@ module Petstore :body => post_body, :auth_names => auth_names, :return_type => 'Array') - if Configuration.debugging - Configuration.logger.debug "API called: PetApi#find_pets_by_tags\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" + if @api_client.config.debugging + @api_client.config.logger.debug "API called: PetApi#find_pets_by_tags\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" end return data, status_code, headers end @@ -256,8 +256,8 @@ module Petstore # @param [Hash] opts the optional parameters # @return [Array<(Pet, Fixnum, Hash)>] Pet data, response status code and response headers def get_pet_by_id_with_http_info(pet_id, opts = {}) - if Configuration.debugging - Configuration.logger.debug "Calling API: PetApi#get_pet_by_id ..." + if @api_client.config.debugging + @api_client.config.logger.debug "Calling API: PetApi#get_pet_by_id ..." end # verify the required parameter 'pet_id' is set @@ -295,8 +295,8 @@ module Petstore :body => post_body, :auth_names => auth_names, :return_type => 'Pet') - if Configuration.debugging - Configuration.logger.debug "API called: PetApi#get_pet_by_id\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" + if @api_client.config.debugging + @api_client.config.logger.debug "API called: PetApi#get_pet_by_id\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" end return data, status_code, headers end @@ -321,8 +321,8 @@ module Petstore # @option opts [String] :status Updated status of the pet # @return [Array<(nil, Fixnum, Hash)>] nil, response status code and response headers def update_pet_with_form_with_http_info(pet_id, opts = {}) - if Configuration.debugging - Configuration.logger.debug "Calling API: PetApi#update_pet_with_form ..." + if @api_client.config.debugging + @api_client.config.logger.debug "Calling API: PetApi#update_pet_with_form ..." end # verify the required parameter 'pet_id' is set @@ -361,8 +361,8 @@ module Petstore :form_params => form_params, :body => post_body, :auth_names => auth_names) - if Configuration.debugging - Configuration.logger.debug "API called: PetApi#update_pet_with_form\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" + if @api_client.config.debugging + @api_client.config.logger.debug "API called: PetApi#update_pet_with_form\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" end return data, status_code, headers end @@ -385,8 +385,8 @@ module Petstore # @option opts [String] :api_key # @return [Array<(nil, Fixnum, Hash)>] nil, response status code and response headers def delete_pet_with_http_info(pet_id, opts = {}) - if Configuration.debugging - Configuration.logger.debug "Calling API: PetApi#delete_pet ..." + if @api_client.config.debugging + @api_client.config.logger.debug "Calling API: PetApi#delete_pet ..." end # verify the required parameter 'pet_id' is set @@ -424,8 +424,8 @@ module Petstore :form_params => form_params, :body => post_body, :auth_names => auth_names) - if Configuration.debugging - Configuration.logger.debug "API called: PetApi#delete_pet\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" + if @api_client.config.debugging + @api_client.config.logger.debug "API called: PetApi#delete_pet\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" end return data, status_code, headers end @@ -450,8 +450,8 @@ module Petstore # @option opts [File] :file file to upload # @return [Array<(nil, Fixnum, Hash)>] nil, response status code and response headers def upload_file_with_http_info(pet_id, opts = {}) - if Configuration.debugging - Configuration.logger.debug "Calling API: PetApi#upload_file ..." + if @api_client.config.debugging + @api_client.config.logger.debug "Calling API: PetApi#upload_file ..." end # verify the required parameter 'pet_id' is set @@ -490,8 +490,8 @@ module Petstore :form_params => form_params, :body => post_body, :auth_names => auth_names) - if Configuration.debugging - Configuration.logger.debug "API called: PetApi#upload_file\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" + if @api_client.config.debugging + @api_client.config.logger.debug "API called: PetApi#upload_file\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" end return data, status_code, headers end diff --git a/samples/client/petstore/ruby/lib/petstore/api/store_api.rb b/samples/client/petstore/ruby/lib/petstore/api/store_api.rb index 548973eefd31..1d8a92e288f9 100644 --- a/samples/client/petstore/ruby/lib/petstore/api/store_api.rb +++ b/samples/client/petstore/ruby/lib/petstore/api/store_api.rb @@ -4,8 +4,8 @@ module Petstore class StoreApi attr_accessor :api_client - def initialize(api_client = nil) - @api_client = api_client || Configuration.api_client + def initialize(api_client = ApiClient.default) + @api_client = api_client end # Returns pet inventories by status @@ -22,8 +22,8 @@ module Petstore # @param [Hash] opts the optional parameters # @return [Array<(Hash, Fixnum, Hash)>] Hash data, response status code and response headers def get_inventory_with_http_info(opts = {}) - if Configuration.debugging - Configuration.logger.debug "Calling API: StoreApi#get_inventory ..." + if @api_client.config.debugging + @api_client.config.logger.debug "Calling API: StoreApi#get_inventory ..." end # resource path @@ -58,8 +58,8 @@ module Petstore :body => post_body, :auth_names => auth_names, :return_type => 'Hash') - if Configuration.debugging - Configuration.logger.debug "API called: StoreApi#get_inventory\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" + if @api_client.config.debugging + @api_client.config.logger.debug "API called: StoreApi#get_inventory\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" end return data, status_code, headers end @@ -80,8 +80,8 @@ module Petstore # @option opts [Order] :body order placed for purchasing the pet # @return [Array<(Order, Fixnum, Hash)>] Order data, response status code and response headers def place_order_with_http_info(opts = {}) - if Configuration.debugging - Configuration.logger.debug "Calling API: StoreApi#place_order ..." + if @api_client.config.debugging + @api_client.config.logger.debug "Calling API: StoreApi#place_order ..." end # resource path @@ -116,8 +116,8 @@ module Petstore :body => post_body, :auth_names => auth_names, :return_type => 'Order') - if Configuration.debugging - Configuration.logger.debug "API called: StoreApi#place_order\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" + if @api_client.config.debugging + @api_client.config.logger.debug "API called: StoreApi#place_order\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" end return data, status_code, headers end @@ -138,8 +138,8 @@ module Petstore # @param [Hash] opts the optional parameters # @return [Array<(Order, Fixnum, Hash)>] Order data, response status code and response headers def get_order_by_id_with_http_info(order_id, opts = {}) - if Configuration.debugging - Configuration.logger.debug "Calling API: StoreApi#get_order_by_id ..." + if @api_client.config.debugging + @api_client.config.logger.debug "Calling API: StoreApi#get_order_by_id ..." end # verify the required parameter 'order_id' is set @@ -177,8 +177,8 @@ module Petstore :body => post_body, :auth_names => auth_names, :return_type => 'Order') - if Configuration.debugging - Configuration.logger.debug "API called: StoreApi#get_order_by_id\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" + if @api_client.config.debugging + @api_client.config.logger.debug "API called: StoreApi#get_order_by_id\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" end return data, status_code, headers end @@ -199,8 +199,8 @@ module Petstore # @param [Hash] opts the optional parameters # @return [Array<(nil, Fixnum, Hash)>] nil, response status code and response headers def delete_order_with_http_info(order_id, opts = {}) - if Configuration.debugging - Configuration.logger.debug "Calling API: StoreApi#delete_order ..." + if @api_client.config.debugging + @api_client.config.logger.debug "Calling API: StoreApi#delete_order ..." end # verify the required parameter 'order_id' is set @@ -237,8 +237,8 @@ module Petstore :form_params => form_params, :body => post_body, :auth_names => auth_names) - if Configuration.debugging - Configuration.logger.debug "API called: StoreApi#delete_order\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" + if @api_client.config.debugging + @api_client.config.logger.debug "API called: StoreApi#delete_order\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" end return data, status_code, headers end diff --git a/samples/client/petstore/ruby/lib/petstore/api/user_api.rb b/samples/client/petstore/ruby/lib/petstore/api/user_api.rb index 35623175f350..e1c8332b8359 100644 --- a/samples/client/petstore/ruby/lib/petstore/api/user_api.rb +++ b/samples/client/petstore/ruby/lib/petstore/api/user_api.rb @@ -4,8 +4,8 @@ module Petstore class UserApi attr_accessor :api_client - def initialize(api_client = nil) - @api_client = api_client || Configuration.api_client + def initialize(api_client = ApiClient.default) + @api_client = api_client end # Create user @@ -24,8 +24,8 @@ module Petstore # @option opts [User] :body Created user object # @return [Array<(nil, Fixnum, Hash)>] nil, response status code and response headers def create_user_with_http_info(opts = {}) - if Configuration.debugging - Configuration.logger.debug "Calling API: UserApi#create_user ..." + if @api_client.config.debugging + @api_client.config.logger.debug "Calling API: UserApi#create_user ..." end # resource path @@ -59,8 +59,8 @@ module Petstore :form_params => form_params, :body => post_body, :auth_names => auth_names) - if Configuration.debugging - Configuration.logger.debug "API called: UserApi#create_user\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" + if @api_client.config.debugging + @api_client.config.logger.debug "API called: UserApi#create_user\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" end return data, status_code, headers end @@ -81,8 +81,8 @@ module Petstore # @option opts [Array] :body List of user object # @return [Array<(nil, Fixnum, Hash)>] nil, response status code and response headers def create_users_with_array_input_with_http_info(opts = {}) - if Configuration.debugging - Configuration.logger.debug "Calling API: UserApi#create_users_with_array_input ..." + if @api_client.config.debugging + @api_client.config.logger.debug "Calling API: UserApi#create_users_with_array_input ..." end # resource path @@ -116,8 +116,8 @@ module Petstore :form_params => form_params, :body => post_body, :auth_names => auth_names) - if Configuration.debugging - Configuration.logger.debug "API called: UserApi#create_users_with_array_input\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" + if @api_client.config.debugging + @api_client.config.logger.debug "API called: UserApi#create_users_with_array_input\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" end return data, status_code, headers end @@ -138,8 +138,8 @@ module Petstore # @option opts [Array] :body List of user object # @return [Array<(nil, Fixnum, Hash)>] nil, response status code and response headers def create_users_with_list_input_with_http_info(opts = {}) - if Configuration.debugging - Configuration.logger.debug "Calling API: UserApi#create_users_with_list_input ..." + if @api_client.config.debugging + @api_client.config.logger.debug "Calling API: UserApi#create_users_with_list_input ..." end # resource path @@ -173,8 +173,8 @@ module Petstore :form_params => form_params, :body => post_body, :auth_names => auth_names) - if Configuration.debugging - Configuration.logger.debug "API called: UserApi#create_users_with_list_input\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" + if @api_client.config.debugging + @api_client.config.logger.debug "API called: UserApi#create_users_with_list_input\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" end return data, status_code, headers end @@ -197,8 +197,8 @@ module Petstore # @option opts [String] :password The password for login in clear text # @return [Array<(String, Fixnum, Hash)>] String data, response status code and response headers def login_user_with_http_info(opts = {}) - if Configuration.debugging - Configuration.logger.debug "Calling API: UserApi#login_user ..." + if @api_client.config.debugging + @api_client.config.logger.debug "Calling API: UserApi#login_user ..." end # resource path @@ -235,8 +235,8 @@ module Petstore :body => post_body, :auth_names => auth_names, :return_type => 'String') - if Configuration.debugging - Configuration.logger.debug "API called: UserApi#login_user\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" + if @api_client.config.debugging + @api_client.config.logger.debug "API called: UserApi#login_user\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" end return data, status_code, headers end @@ -255,8 +255,8 @@ module Petstore # @param [Hash] opts the optional parameters # @return [Array<(nil, Fixnum, Hash)>] nil, response status code and response headers def logout_user_with_http_info(opts = {}) - if Configuration.debugging - Configuration.logger.debug "Calling API: UserApi#logout_user ..." + if @api_client.config.debugging + @api_client.config.logger.debug "Calling API: UserApi#logout_user ..." end # resource path @@ -290,8 +290,8 @@ module Petstore :form_params => form_params, :body => post_body, :auth_names => auth_names) - if Configuration.debugging - Configuration.logger.debug "API called: UserApi#logout_user\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" + if @api_client.config.debugging + @api_client.config.logger.debug "API called: UserApi#logout_user\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" end return data, status_code, headers end @@ -312,8 +312,8 @@ module Petstore # @param [Hash] opts the optional parameters # @return [Array<(User, Fixnum, Hash)>] User data, response status code and response headers def get_user_by_name_with_http_info(username, opts = {}) - if Configuration.debugging - Configuration.logger.debug "Calling API: UserApi#get_user_by_name ..." + if @api_client.config.debugging + @api_client.config.logger.debug "Calling API: UserApi#get_user_by_name ..." end # verify the required parameter 'username' is set @@ -351,8 +351,8 @@ module Petstore :body => post_body, :auth_names => auth_names, :return_type => 'User') - if Configuration.debugging - Configuration.logger.debug "API called: UserApi#get_user_by_name\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" + if @api_client.config.debugging + @api_client.config.logger.debug "API called: UserApi#get_user_by_name\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" end return data, status_code, headers end @@ -375,8 +375,8 @@ module Petstore # @option opts [User] :body Updated user object # @return [Array<(nil, Fixnum, Hash)>] nil, response status code and response headers def update_user_with_http_info(username, opts = {}) - if Configuration.debugging - Configuration.logger.debug "Calling API: UserApi#update_user ..." + if @api_client.config.debugging + @api_client.config.logger.debug "Calling API: UserApi#update_user ..." end # verify the required parameter 'username' is set @@ -413,8 +413,8 @@ module Petstore :form_params => form_params, :body => post_body, :auth_names => auth_names) - if Configuration.debugging - Configuration.logger.debug "API called: UserApi#update_user\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" + if @api_client.config.debugging + @api_client.config.logger.debug "API called: UserApi#update_user\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" end return data, status_code, headers end @@ -435,8 +435,8 @@ module Petstore # @param [Hash] opts the optional parameters # @return [Array<(nil, Fixnum, Hash)>] nil, response status code and response headers def delete_user_with_http_info(username, opts = {}) - if Configuration.debugging - Configuration.logger.debug "Calling API: UserApi#delete_user ..." + if @api_client.config.debugging + @api_client.config.logger.debug "Calling API: UserApi#delete_user ..." end # verify the required parameter 'username' is set @@ -473,8 +473,8 @@ module Petstore :form_params => form_params, :body => post_body, :auth_names => auth_names) - if Configuration.debugging - Configuration.logger.debug "API called: UserApi#delete_user\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" + if @api_client.config.debugging + @api_client.config.logger.debug "API called: UserApi#delete_user\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" end return data, status_code, headers end diff --git a/samples/client/petstore/ruby/lib/petstore/api_client.rb b/samples/client/petstore/ruby/lib/petstore/api_client.rb index 0648ee54cf35..52a3eb43855c 100644 --- a/samples/client/petstore/ruby/lib/petstore/api_client.rb +++ b/samples/client/petstore/ruby/lib/petstore/api_client.rb @@ -7,24 +7,27 @@ require 'uri' module Petstore class ApiClient - - attr_accessor :host + # The Configuration object holding settings to be used in the API client. + attr_accessor :config # Defines the headers to be used in HTTP requests of all API calls by default. # # @return [Hash] attr_accessor :default_headers - def initialize(host = nil) - @host = host || Configuration.base_url - @format = 'json' + def initialize(config = Configuration.default) + @config = config @user_agent = "ruby-swagger-#{VERSION}" @default_headers = { - 'Content-Type' => "application/#{@format.downcase}", + 'Content-Type' => "application/json", 'User-Agent' => @user_agent } end + def self.default + @@default ||= ApiClient.new + end + # Call an API with given options. # # @return [Array<(Object, Fixnum, Hash)>] an array of 3 elements: @@ -33,8 +36,8 @@ module Petstore request = build_request(http_method, path, opts) response = request.run - if Configuration.debugging - Configuration.logger.debug "HTTP response body ~BEGIN~\n#{response.body}\n~END~\n" + if @config.debugging + @config.logger.debug "HTTP response body ~BEGIN~\n#{response.body}\n~END~\n" end unless response.success? @@ -68,18 +71,18 @@ module Petstore :method => http_method, :headers => header_params, :params => query_params, - :ssl_verifypeer => Configuration.verify_ssl, - :sslcert => Configuration.cert_file, - :sslkey => Configuration.key_file, - :cainfo => Configuration.ssl_ca_cert, - :verbose => Configuration.debugging + :ssl_verifypeer => @config.verify_ssl, + :sslcert => @config.cert_file, + :sslkey => @config.key_file, + :cainfo => @config.ssl_ca_cert, + :verbose => @config.debugging } if [:post, :patch, :put, :delete].include?(http_method) req_body = build_request_body(header_params, form_params, opts[:body]) req_opts.update :body => req_body - if Configuration.debugging - Configuration.logger.debug "HTTP request body param ~BEGIN~\n#{req_body}\n~END~\n" + if @config.debugging + @config.logger.debug "HTTP request body param ~BEGIN~\n#{req_body}\n~END~\n" end end @@ -168,7 +171,7 @@ module Petstore # @see Configuration#temp_folder_path # @return [File] the file downloaded def download_file(response) - tmp_file = Tempfile.new '', Configuration.temp_folder_path + tmp_file = Tempfile.new '', @config.temp_folder_path content_disposition = response.headers['Content-Disposition'] if content_disposition filename = content_disposition[/filename=['"]?([^'"\s]+)['"]?/, 1] @@ -180,15 +183,15 @@ module Petstore tmp_file.close! File.open(path, 'w') { |file| file.write(response.body) } - Configuration.logger.info "File written to #{path}. Please move the file to a proper "\ - "folder for further processing and delete the temp afterwards" + @config.logger.info "File written to #{path}. Please move the file to a proper folder "\ + "for further processing and delete the temp afterwards" File.new(path) end def build_request_url(path) # Add leading and trailing slashes to path path = "/#{path}".gsub(/\/+/, '/') - URI.encode(host + path) + URI.encode(@config.base_url + path) end def build_request_body(header_params, form_params, body) @@ -216,7 +219,7 @@ module Petstore # Update hearder and query params based on authentication settings. def update_params_for_auth!(header_params, query_params, auth_names) Array(auth_names).each do |auth_name| - auth_setting = Configuration.auth_settings[auth_name] + auth_setting = @config.auth_settings[auth_name] next unless auth_setting case auth_setting[:in] when 'header' then header_params[auth_setting[:key]] = auth_setting[:value] diff --git a/samples/client/petstore/ruby/lib/petstore/configuration.rb b/samples/client/petstore/ruby/lib/petstore/configuration.rb index 4f7bd1c1b803..7173a4450c64 100644 --- a/samples/client/petstore/ruby/lib/petstore/configuration.rb +++ b/samples/client/petstore/ruby/lib/petstore/configuration.rb @@ -1,14 +1,7 @@ require 'uri' -require 'singleton' module Petstore class Configuration - - include Singleton - - # Default api client - attr_accessor :api_client - # Defines url scheme attr_accessor :scheme @@ -94,17 +87,6 @@ module Petstore attr_accessor :force_ending_format - class << self - def method_missing(method_name, *args, &block) - config = Configuration.instance - if config.respond_to?(method_name) - config.send(method_name, *args, &block) - else - super - end - end - end - def initialize @scheme = 'http' @host = 'petstore.swagger.io' @@ -118,10 +100,17 @@ module Petstore @inject_format = false @force_ending_format = false @logger = defined?(Rails) ? Rails.logger : Logger.new(STDOUT) + + yield(self) if block_given? end - def api_client - @api_client ||= ApiClient.new + # The default Configuration object. + def self.default + @@default ||= Configuration.new + end + + def configure + yield(self) if block_given? end def scheme=(scheme) diff --git a/samples/client/petstore/ruby/spec/api_client_spec.rb b/samples/client/petstore/ruby/spec/api_client_spec.rb index 7b2478ea67c3..c2bfef4e8e4e 100644 --- a/samples/client/petstore/ruby/spec/api_client_spec.rb +++ b/samples/client/petstore/ruby/spec/api_client_spec.rb @@ -10,34 +10,34 @@ describe Petstore::ApiClient do context 'host' do it 'removes http from host' do Petstore.configure { |c| c.host = 'http://example.com' } - Petstore.configure.host.should == 'example.com' + Petstore::Configuration.default.host.should == 'example.com' end it 'removes https from host' do Petstore.configure { |c| c.host = 'https://wookiee.com' } - Petstore.configure.host.should == 'wookiee.com' + Petstore::ApiClient.default.config.host.should == 'wookiee.com' end it 'removes trailing path from host' do Petstore.configure { |c| c.host = 'hobo.com/v4' } - Petstore.configure.host.should == 'hobo.com' + Petstore::Configuration.default.host.should == 'hobo.com' end end context 'base_path' do it "prepends a slash to base_path" do Petstore.configure { |c| c.base_path = 'v4/dog' } - Petstore.configure.base_path.should == '/v4/dog' + Petstore::Configuration.default.base_path.should == '/v4/dog' end it "doesn't prepend a slash if one is already there" do Petstore.configure { |c| c.base_path = '/v4/dog' } - Petstore.configure.base_path.should == '/v4/dog' + Petstore::Configuration.default.base_path.should == '/v4/dog' end it "ends up as a blank string if nil" do Petstore.configure { |c| c.base_path = nil } - Petstore.configure.base_path.should == '' + Petstore::Configuration.default.base_path.should == '' end end @@ -53,13 +53,26 @@ describe Petstore::ApiClient do end api_client = Petstore::ApiClient.new + + config2 = Petstore::Configuration.new do |c| + c.api_key_prefix['api_key'] = 'PREFIX2' + c.api_key['api_key'] = 'special-key2' + end + api_client2 = Petstore::ApiClient.new(config2) + auth_names = ['api_key', 'unknown'] + header_params = {} query_params = {} - auth_names = ['api_key', 'unknown'] api_client.update_params_for_auth! header_params, query_params, auth_names header_params.should == {'api_key' => 'PREFIX special-key'} query_params.should == {} + + header_params = {} + query_params = {} + api_client2.update_params_for_auth! header_params, query_params, auth_names + header_params.should == {'api_key' => 'PREFIX2 special-key2'} + query_params.should == {} end it "sets header api-key parameter without prefix" do diff --git a/samples/client/petstore/ruby/spec/configuration_spec.rb b/samples/client/petstore/ruby/spec/configuration_spec.rb index 9f86f5602b74..eb29b54c2a79 100644 --- a/samples/client/petstore/ruby/spec/configuration_spec.rb +++ b/samples/client/petstore/ruby/spec/configuration_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Petstore::Configuration do - let(:config) { Petstore::Configuration.instance } + let(:config) { Petstore::Configuration.default } before(:each) do Petstore.configure do |c| diff --git a/samples/client/petstore/ruby/spec/spec_helper.rb b/samples/client/petstore/ruby/spec/spec_helper.rb index b8ba0f739756..26da98f9c422 100644 --- a/samples/client/petstore/ruby/spec/spec_helper.rb +++ b/samples/client/petstore/ruby/spec/spec_helper.rb @@ -36,7 +36,7 @@ end # help #end -API_CLIENT = Petstore::ApiClient.new +API_CLIENT = Petstore::ApiClient.new(Petstore::Configuration.new) # always delete and then re-create the pet object with 10002 def prepare_pet(pet_api) From f5693b6c7332b50f211e7df5740c8a56c65a522b Mon Sep 17 00:00:00 2001 From: wing328 Date: Thu, 10 Dec 2015 16:35:38 +0800 Subject: [PATCH 35/71] update sample and test case for java feign --- samples/client/petstore/java/feign/README.md | 4 ++-- samples/client/petstore/java/feign/build.gradle | 2 +- samples/client/petstore/java/feign/pom.xml | 4 ++-- .../client/petstore/java/feign/settings.gradle | 2 +- .../main/java/io/swagger/client/ApiClient.java | 2 +- .../java/io/swagger/client/FormAwareEncoder.java | 2 +- .../main/java/io/swagger/client/StringUtil.java | 2 +- .../main/java/io/swagger/client/api/PetApi.java | 16 ++++++---------- .../java/io/swagger/client/api/StoreApi.java | 7 ++----- .../main/java/io/swagger/client/api/UserApi.java | 5 +---- .../java/io/swagger/client/model/Category.java | 8 ++------ .../main/java/io/swagger/client/model/Order.java | 12 +++++------- .../main/java/io/swagger/client/model/Pet.java | 12 +++++------- .../main/java/io/swagger/client/model/Tag.java | 8 ++------ .../main/java/io/swagger/client/model/User.java | 8 ++------ .../io/swagger/petstore/test/PetApiTest.java | 4 ++-- .../io/swagger/petstore/test/StoreApiTest.java | 8 ++++---- .../io/swagger/petstore/test/UserApiTest.java | 6 ++++-- 18 files changed, 44 insertions(+), 68 deletions(-) diff --git a/samples/client/petstore/java/feign/README.md b/samples/client/petstore/java/feign/README.md index 8afc37518fc7..3ca7abfb5573 100644 --- a/samples/client/petstore/java/feign/README.md +++ b/samples/client/petstore/java/feign/README.md @@ -1,4 +1,4 @@ -# swagger-java-client +# swagger-petstore-feign ## Requirements @@ -25,7 +25,7 @@ After the client libarary is installed/deployed, you can use it in your Maven pr ```xml io.swagger - swagger-java-client + swagger-petstore-feign 1.0.0 compile diff --git a/samples/client/petstore/java/feign/build.gradle b/samples/client/petstore/java/feign/build.gradle index 383e0a1dc956..0bfcfbec71f2 100644 --- a/samples/client/petstore/java/feign/build.gradle +++ b/samples/client/petstore/java/feign/build.gradle @@ -80,7 +80,7 @@ if(hasProperty('target') && target == 'android') { install { repositories.mavenInstaller { - pom.artifactId = 'swagger-java-client' + pom.artifactId = 'swagger-petstore-feign' } } diff --git a/samples/client/petstore/java/feign/pom.xml b/samples/client/petstore/java/feign/pom.xml index 967bdabcc6bc..5f7e95518625 100644 --- a/samples/client/petstore/java/feign/pom.xml +++ b/samples/client/petstore/java/feign/pom.xml @@ -2,9 +2,9 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 4.0.0 io.swagger - swagger-java-client + swagger-petstore-feign jar - swagger-java-client + swagger-petstore-feign 1.0.0 scm:git:git@github.com:swagger-api/swagger-mustache.git diff --git a/samples/client/petstore/java/feign/settings.gradle b/samples/client/petstore/java/feign/settings.gradle index 55640f75122e..a25109c126eb 100644 --- a/samples/client/petstore/java/feign/settings.gradle +++ b/samples/client/petstore/java/feign/settings.gradle @@ -1 +1 @@ -rootProject.name = "swagger-java-client" \ No newline at end of file +rootProject.name = "swagger-petstore-feign" \ No newline at end of file diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/ApiClient.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/ApiClient.java index 42439dbdf24c..fae831971e9f 100644 --- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/ApiClient.java +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/ApiClient.java @@ -8,7 +8,7 @@ import feign.jackson.JacksonDecoder; import feign.jackson.JacksonEncoder; import feign.slf4j.Slf4jLogger; -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-09T22:59:22.180-05:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-10T16:26:30.730+08:00") public class ApiClient { public interface Api {} diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/FormAwareEncoder.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/FormAwareEncoder.java index e38faaf009a2..e9ee05b16a4b 100644 --- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/FormAwareEncoder.java +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/FormAwareEncoder.java @@ -14,7 +14,7 @@ import feign.codec.EncodeException; import feign.codec.Encoder; import feign.RequestTemplate; -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-09T22:59:22.180-05:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-10T16:26:30.730+08:00") public class FormAwareEncoder implements Encoder { public static final String UTF_8 = "utf-8"; private static final String LINE_FEED = "\r\n"; diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/StringUtil.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/StringUtil.java index cc437fee0c00..c843634389db 100644 --- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/StringUtil.java +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/StringUtil.java @@ -1,6 +1,6 @@ package io.swagger.client; -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-09T22:59:22.180-05:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-10T16:26:30.730+08:00") public class StringUtil { /** * Check if the given array contains the given value (with case-insensitive comparison). diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/PetApi.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/PetApi.java index 536e953e699a..cdf1c4d75d36 100644 --- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/PetApi.java +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/PetApi.java @@ -4,14 +4,11 @@ import io.swagger.client.ApiClient; import io.swagger.client.model.Pet; import java.io.File; -import io.swagger.client.model.ApiResponse; - import java.util.*; - import feign.*; -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-09T22:59:22.180-05:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-10T16:26:30.730+08:00") public interface PetApi extends ApiClient.Api { @@ -69,8 +66,8 @@ public interface PetApi extends ApiClient.Api { /** * Find pet by ID - * Returns a single pet - * @param petId ID of pet to return + * Returns a pet when ID < 10. ID > 10 or nonintegers will simulate API error conditions + * @param petId ID of pet that needs to be fetched * @return Pet */ @RequestLine("GET /pet/{petId}") @@ -93,7 +90,7 @@ public interface PetApi extends ApiClient.Api { "Content-type: application/x-www-form-urlencoded", "Accepts: application/json", }) - void updatePetWithForm(@Param("petId") Long petId, @Param("name") String name, @Param("status") String status); + void updatePetWithForm(@Param("petId") String petId, @Param("name") String name, @Param("status") String status); /** * Deletes a pet @@ -116,14 +113,13 @@ public interface PetApi extends ApiClient.Api { * @param petId ID of pet to update * @param additionalMetadata Additional data to pass to server * @param file file to upload - * @return ApiResponse + * @return void */ @RequestLine("POST /pet/{petId}/uploadImage") @Headers({ "Content-type: multipart/form-data", "Accepts: application/json", }) - ApiResponse uploadFile(@Param("petId") Long petId, @Param("additionalMetadata") String additionalMetadata, @Param("file") File file); + void uploadFile(@Param("petId") Long petId, @Param("additionalMetadata") String additionalMetadata, @Param("file") File file); - } diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/StoreApi.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/StoreApi.java index 552c62db9193..3983ee7d0461 100644 --- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/StoreApi.java +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/StoreApi.java @@ -5,12 +5,10 @@ import io.swagger.client.ApiClient; import java.util.Map; import io.swagger.client.model.Order; - import java.util.*; - import feign.*; -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-09T22:59:22.180-05:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-10T16:26:30.730+08:00") public interface StoreApi extends ApiClient.Api { @@ -50,7 +48,7 @@ public interface StoreApi extends ApiClient.Api { "Content-type: application/json", "Accepts: application/json", }) - Order getOrderById(@Param("orderId") Long orderId); + Order getOrderById(@Param("orderId") String orderId); /** * Delete purchase order by ID @@ -65,5 +63,4 @@ public interface StoreApi extends ApiClient.Api { }) void deleteOrder(@Param("orderId") String orderId); - } diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/UserApi.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/UserApi.java index 610bd3997001..95d4ade78d6c 100644 --- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/UserApi.java +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/UserApi.java @@ -5,12 +5,10 @@ import io.swagger.client.ApiClient; import io.swagger.client.model.User; import java.util.*; - import java.util.*; - import feign.*; -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-09T22:59:22.180-05:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-10T16:26:30.730+08:00") public interface UserApi extends ApiClient.Api { @@ -119,5 +117,4 @@ public interface UserApi extends ApiClient.Api { }) void deleteUser(@Param("username") String username); - } diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Category.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Category.java index 3a22c2b9c604..463da28c6384 100644 --- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Category.java +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Category.java @@ -3,16 +3,14 @@ package io.swagger.client.model; import io.swagger.client.StringUtil; - import java.util.Objects; import io.swagger.annotations.*; -import com.fasterxml.jackson.annotation.JsonProperty; - +import com.fasterxml.jackson.annotation.*; @ApiModel(description = "") -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-09T22:59:22.180-05:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-10T16:26:30.730+08:00") public class Category { private Long id = null; @@ -73,5 +71,3 @@ public class Category { return sb.toString(); } } - - diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Order.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Order.java index 9b87b66c9e6a..9b4907677594 100644 --- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Order.java +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Order.java @@ -4,16 +4,14 @@ import io.swagger.client.StringUtil; import java.util.Date; - import java.util.Objects; import io.swagger.annotations.*; -import com.fasterxml.jackson.annotation.JsonProperty; - +import com.fasterxml.jackson.annotation.*; @ApiModel(description = "") -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-09T22:59:22.180-05:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-10T16:26:30.730+08:00") public class Order { private Long id = null; @@ -21,6 +19,7 @@ public class Order { private Integer quantity = null; private Date shipDate = null; + public enum StatusEnum { PLACED("placed"), APPROVED("approved"), @@ -33,13 +32,14 @@ public enum StatusEnum { } @Override + @JsonValue public String toString() { return value; } } private StatusEnum status = null; - private Boolean complete = false; + private Boolean complete = null; /** @@ -153,5 +153,3 @@ public enum StatusEnum { return sb.toString(); } } - - diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Pet.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Pet.java index 07c18075bd2c..471bbe34b006 100644 --- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Pet.java +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Pet.java @@ -2,20 +2,18 @@ package io.swagger.client.model; import io.swagger.client.StringUtil; import io.swagger.client.model.Category; -import java.util.*; import io.swagger.client.model.Tag; - +import java.util.*; import java.util.Objects; import io.swagger.annotations.*; -import com.fasterxml.jackson.annotation.JsonProperty; - +import com.fasterxml.jackson.annotation.*; @ApiModel(description = "") -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-09T22:59:22.180-05:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-10T16:26:30.730+08:00") public class Pet { private Long id = null; @@ -24,6 +22,7 @@ public class Pet { private List photoUrls = new ArrayList(); private List tags = new ArrayList(); + public enum StatusEnum { AVAILABLE("available"), PENDING("pending"), @@ -36,6 +35,7 @@ public enum StatusEnum { } @Override + @JsonValue public String toString() { return value; } @@ -155,5 +155,3 @@ public enum StatusEnum { return sb.toString(); } } - - diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Tag.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Tag.java index 80b3919e5325..02b5b85be403 100644 --- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Tag.java +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/Tag.java @@ -3,16 +3,14 @@ package io.swagger.client.model; import io.swagger.client.StringUtil; - import java.util.Objects; import io.swagger.annotations.*; -import com.fasterxml.jackson.annotation.JsonProperty; - +import com.fasterxml.jackson.annotation.*; @ApiModel(description = "") -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-09T22:59:22.180-05:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-10T16:26:30.730+08:00") public class Tag { private Long id = null; @@ -73,5 +71,3 @@ public class Tag { return sb.toString(); } } - - diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/User.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/User.java index efa18d38dcf8..4d072f67d477 100644 --- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/User.java +++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/model/User.java @@ -3,16 +3,14 @@ package io.swagger.client.model; import io.swagger.client.StringUtil; - import java.util.Objects; import io.swagger.annotations.*; -import com.fasterxml.jackson.annotation.JsonProperty; - +import com.fasterxml.jackson.annotation.*; @ApiModel(description = "") -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-09T22:59:22.180-05:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-10T16:26:30.730+08:00") public class User { private Long id = null; @@ -164,5 +162,3 @@ public class User { return sb.toString(); } } - - diff --git a/samples/client/petstore/java/feign/src/test/java/io/swagger/petstore/test/PetApiTest.java b/samples/client/petstore/java/feign/src/test/java/io/swagger/petstore/test/PetApiTest.java index 402d60b37c29..aef8ab25610f 100644 --- a/samples/client/petstore/java/feign/src/test/java/io/swagger/petstore/test/PetApiTest.java +++ b/samples/client/petstore/java/feign/src/test/java/io/swagger/petstore/test/PetApiTest.java @@ -119,7 +119,7 @@ public class PetApiTest { Pet fetched = api.getPetById(pet.getId()); - api.updatePetWithForm(fetched.getId(), "furt", null); + api.updatePetWithForm(fetched.getId().toString(), "furt", null); Pet updated = api.getPetById(fetched.getId()); assertEquals(updated.getName(), "furt"); @@ -196,4 +196,4 @@ public class PetApiTest { return pet; } -} \ No newline at end of file +} diff --git a/samples/client/petstore/java/feign/src/test/java/io/swagger/petstore/test/StoreApiTest.java b/samples/client/petstore/java/feign/src/test/java/io/swagger/petstore/test/StoreApiTest.java index b91c391e9918..dd5bf4e71f4c 100644 --- a/samples/client/petstore/java/feign/src/test/java/io/swagger/petstore/test/StoreApiTest.java +++ b/samples/client/petstore/java/feign/src/test/java/io/swagger/petstore/test/StoreApiTest.java @@ -30,7 +30,7 @@ public class StoreApiTest { Order order = createOrder(); api.placeOrder(order); - Order fetched = api.getOrderById(order.getId()); + Order fetched = api.getOrderById(order.getId().toString()); assertEquals(order.getId(), fetched.getId()); assertEquals(order.getPetId(), fetched.getPetId()); assertEquals(order.getQuantity(), fetched.getQuantity()); @@ -41,12 +41,12 @@ public class StoreApiTest { Order order = createOrder(); api.placeOrder(order); - Order fetched = api.getOrderById(order.getId()); + Order fetched = api.getOrderById(order.getId().toString()); assertEquals(fetched.getId(), order.getId()); api.deleteOrder(String.valueOf(order.getId())); - api.getOrderById(order.getId()); + api.getOrderById(order.getId().toString()); // fail("expected an error"); } @@ -61,4 +61,4 @@ public class StoreApiTest { return order; } -} \ No newline at end of file +} diff --git a/samples/client/petstore/java/feign/src/test/java/io/swagger/petstore/test/UserApiTest.java b/samples/client/petstore/java/feign/src/test/java/io/swagger/petstore/test/UserApiTest.java index dc2d3ac17cac..1615dbf1dce7 100644 --- a/samples/client/petstore/java/feign/src/test/java/io/swagger/petstore/test/UserApiTest.java +++ b/samples/client/petstore/java/feign/src/test/java/io/swagger/petstore/test/UserApiTest.java @@ -55,7 +55,9 @@ public class UserApiTest { assertEquals(user1.getId(), fetched.getId()); } - @Test + // ignore for the time being, please refer to the following for more info: + // https://github.com/swagger-api/swagger-codegen/issues/1660 + @Ignore @Test public void testLoginUser() throws Exception { User user = createUser(); api.createUser(user); @@ -82,4 +84,4 @@ public class UserApiTest { return user; } -} \ No newline at end of file +} From 5ef169de1585f330f3503654abe802bd5b9c8bba Mon Sep 17 00:00:00 2001 From: wing328 Date: Thu, 10 Dec 2015 16:35:38 +0800 Subject: [PATCH 36/71] update sample and test case for java feign --- pom.xml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/pom.xml b/pom.xml index 43df2b04be05..267de93280e9 100644 --- a/pom.xml +++ b/pom.xml @@ -377,6 +377,18 @@ samples/client/petstore/java/retrofit2 + + java-client-feign + + + env + java + + + + samples/client/petstore/java/feign + + scala-client From 9faf6f4068bd0a905608dd97fe8d395987670193 Mon Sep 17 00:00:00 2001 From: wing328 Date: Thu, 10 Dec 2015 18:55:28 +0800 Subject: [PATCH 37/71] add php profiler for petstore, fix empty/null string check --- .../src/main/resources/php/api.mustache | 6 +++--- .../php/SwaggerClient-php/lib/Api/PetApi.php | 16 ++++++++-------- .../php/SwaggerClient-php/lib/Api/StoreApi.php | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/modules/swagger-codegen/src/main/resources/php/api.mustache b/modules/swagger-codegen/src/main/resources/php/api.mustache index 22ae27fc77d0..cce59f4d94b5 100644 --- a/modules/swagger-codegen/src/main/resources/php/api.mustache +++ b/modules/swagger-codegen/src/main/resources/php/api.mustache @@ -184,14 +184,14 @@ use \{{invokerPackage}}\ObjectSerializer; {{#authMethods}}{{#isApiKey}} // this endpoint requires API key authentication $apiKey = $this->apiClient->getApiKeyWithPrefix('{{keyParamName}}'); - if ($apiKey !== null) { + if (strlen($apiKey) !== 0) { {{#isKeyInHeader}}$headerParams['{{keyParamName}}'] = $apiKey;{{/isKeyInHeader}}{{#isKeyInQuery}}$queryParams['{{keyParamName}}'] = $apiKey;{{/isKeyInQuery}} }{{/isApiKey}} {{#isBasic}}// this endpoint requires HTTP basic authentication - if ($this->apiClient->getConfig()->getUsername() !== null or $this->apiClient->getConfig()->getPassword() !== null) { + if (strlen($this->apiClient->getConfig()->getUsername()) !== 0 or strlen($this->apiClient->getConfig()->getPassword()) !== 0) { $headerParams['Authorization'] = 'Basic ' . base64_encode($this->apiClient->getConfig()->getUsername() . ":" . $this->apiClient->getConfig()->getPassword()); }{{/isBasic}}{{#isOAuth}}// this endpoint requires OAuth (access token) - if ($this->apiClient->getConfig()->getAccessToken() !== null) { + if (strlen($this->apiClient->getConfig()->getAccessToken()) !== 0) { $headerParams['Authorization'] = 'Bearer ' . $this->apiClient->getConfig()->getAccessToken(); }{{/isOAuth}} {{/authMethods}} diff --git a/samples/client/petstore/php/SwaggerClient-php/lib/Api/PetApi.php b/samples/client/petstore/php/SwaggerClient-php/lib/Api/PetApi.php index 18aeba64072d..bd82444f4fe0 100644 --- a/samples/client/petstore/php/SwaggerClient-php/lib/Api/PetApi.php +++ b/samples/client/petstore/php/SwaggerClient-php/lib/Api/PetApi.php @@ -152,7 +152,7 @@ class PetApi } // this endpoint requires OAuth (access token) - if ($this->apiClient->getConfig()->getAccessToken() !== null) { + if (strlen($this->apiClient->getConfig()->getAccessToken()) !== 0) { $headerParams['Authorization'] = 'Bearer ' . $this->apiClient->getConfig()->getAccessToken(); } @@ -235,7 +235,7 @@ class PetApi } // this endpoint requires OAuth (access token) - if ($this->apiClient->getConfig()->getAccessToken() !== null) { + if (strlen($this->apiClient->getConfig()->getAccessToken()) !== 0) { $headerParams['Authorization'] = 'Bearer ' . $this->apiClient->getConfig()->getAccessToken(); } @@ -317,7 +317,7 @@ class PetApi } // this endpoint requires OAuth (access token) - if ($this->apiClient->getConfig()->getAccessToken() !== null) { + if (strlen($this->apiClient->getConfig()->getAccessToken()) !== 0) { $headerParams['Authorization'] = 'Bearer ' . $this->apiClient->getConfig()->getAccessToken(); } @@ -407,7 +407,7 @@ class PetApi } // this endpoint requires OAuth (access token) - if ($this->apiClient->getConfig()->getAccessToken() !== null) { + if (strlen($this->apiClient->getConfig()->getAccessToken()) !== 0) { $headerParams['Authorization'] = 'Bearer ' . $this->apiClient->getConfig()->getAccessToken(); } @@ -506,7 +506,7 @@ class PetApi // this endpoint requires API key authentication $apiKey = $this->apiClient->getApiKeyWithPrefix('api_key'); - if ($apiKey !== null) { + if (strlen($apiKey) !== 0) { $headerParams['api_key'] = $apiKey; } @@ -621,7 +621,7 @@ class PetApi } // this endpoint requires OAuth (access token) - if ($this->apiClient->getConfig()->getAccessToken() !== null) { + if (strlen($this->apiClient->getConfig()->getAccessToken()) !== 0) { $headerParams['Authorization'] = 'Bearer ' . $this->apiClient->getConfig()->getAccessToken(); } @@ -716,7 +716,7 @@ class PetApi } // this endpoint requires OAuth (access token) - if ($this->apiClient->getConfig()->getAccessToken() !== null) { + if (strlen($this->apiClient->getConfig()->getAccessToken()) !== 0) { $headerParams['Authorization'] = 'Bearer ' . $this->apiClient->getConfig()->getAccessToken(); } @@ -828,7 +828,7 @@ class PetApi } // this endpoint requires OAuth (access token) - if ($this->apiClient->getConfig()->getAccessToken() !== null) { + if (strlen($this->apiClient->getConfig()->getAccessToken()) !== 0) { $headerParams['Authorization'] = 'Bearer ' . $this->apiClient->getConfig()->getAccessToken(); } diff --git a/samples/client/petstore/php/SwaggerClient-php/lib/Api/StoreApi.php b/samples/client/petstore/php/SwaggerClient-php/lib/Api/StoreApi.php index 4539aeeeab45..4faed9a36baa 100644 --- a/samples/client/petstore/php/SwaggerClient-php/lib/Api/StoreApi.php +++ b/samples/client/petstore/php/SwaggerClient-php/lib/Api/StoreApi.php @@ -147,7 +147,7 @@ class StoreApi // this endpoint requires API key authentication $apiKey = $this->apiClient->getApiKeyWithPrefix('api_key'); - if ($apiKey !== null) { + if (strlen($apiKey) !== 0) { $headerParams['api_key'] = $apiKey; } From 84ee958117d5d6510966c1c0b29028ad7cc4885d Mon Sep 17 00:00:00 2001 From: evigeant Date: Tue, 1 Dec 2015 11:23:02 -0500 Subject: [PATCH 38/71] Simplified Jersey ApiClient by delegating much serialization to Jersey --- .../main/resources/Java/ApiClient.mustache | 84 ++++++------------- .../src/main/resources/Java/api.mustache | 9 +- 2 files changed, 31 insertions(+), 62 deletions(-) diff --git a/modules/swagger-codegen/src/main/resources/Java/ApiClient.mustache b/modules/swagger-codegen/src/main/resources/Java/ApiClient.mustache index 562df7e1f796..679297f033f4 100644 --- a/modules/swagger-codegen/src/main/resources/Java/ApiClient.mustache +++ b/modules/swagger-codegen/src/main/resources/Java/ApiClient.mustache @@ -405,11 +405,26 @@ public class ApiClient { * Serialize the given Java object into string according the given * Content-Type (only JSON is supported for now). */ - public String serialize(Object obj, String contentType) throws ApiException { + public Object serialize(Object obj, String contentType, Map formParams) throws ApiException { if (isJsonMime(contentType)) { return json.serialize(obj); + } else if (contentType.startsWith("multipart/form-data")) { + FormDataMultiPart mp = new FormDataMultiPart(); + for (Entry param: formParams.entrySet()) { + if (param.getValue() instanceof File) { + File file = (File) param.getValue(); + mp.bodyPart(new FileDataBodyPart(param.getKey(), file, MediaType.MULTIPART_FORM_DATA_TYPE)); + } else { + mp.field(param.getKey(), parameterToString(param.getValue()), MediaType.MULTIPART_FORM_DATA_TYPE); + } + } + return mp; + } else if (contentType.startsWith("application/x-www-form-urlencoded")) { + return this.getXWWWFormUrlencodedParams(formParams); } else { - throw new ApiException(400, "can not serialize object into Content-Type: " + contentType); + // We let Jersey attempt to serialize the body + return obj; + //throw new ApiException(400, "can not serialize object into Content-Type: " + contentType); } } @@ -444,10 +459,10 @@ public class ApiClient { } } - private ClientResponse getAPIResponse(String path, String method, List queryParams, Object body, byte[] binaryBody, Map headerParams, Map formParams, String accept, String contentType, String[] authNames) throws ApiException { + private ClientResponse getAPIResponse(String path, String method, List queryParams, Object body, Map headerParams, Map formParams, String accept, String contentType, String[] authNames) throws ApiException { - if (body != null && binaryBody != null){ - throw new ApiException(500, "either body or binaryBody must be null"); + if (body != null && !formParams.isEmpty()){ + throw new ApiException(500, "Cannot have body and form params"); } updateParamsForAuth(authNames, queryParams, headerParams); @@ -484,61 +499,16 @@ public class ApiClient { } } - String encodedFormParams = null; - if (contentType.startsWith("multipart/form-data")) { - FormDataMultiPart mp = new FormDataMultiPart(); - for (Entry param: formParams.entrySet()) { - if (param.getValue() instanceof File) { - File file = (File) param.getValue(); - mp.bodyPart(new FileDataBodyPart(param.getKey(), file, MediaType.MULTIPART_FORM_DATA_TYPE)); - } else { - mp.field(param.getKey(), parameterToString(param.getValue()), MediaType.MULTIPART_FORM_DATA_TYPE); - } - } - body = mp; - } else if (contentType.startsWith("application/x-www-form-urlencoded")) { - encodedFormParams = this.getXWWWFormUrlencodedParams(formParams); - } - ClientResponse response = null; if ("GET".equals(method)) { response = (ClientResponse) builder.get(ClientResponse.class); } else if ("POST".equals(method)) { - if (encodedFormParams != null) { - response = builder.type(contentType).post(ClientResponse.class, encodedFormParams); - } else if (body == null) { - if(binaryBody == null) - response = builder.post(ClientResponse.class, null); - else - response = builder.type(contentType).post(ClientResponse.class, binaryBody); - } else if (body instanceof FormDataMultiPart) { - response = builder.type(contentType).post(ClientResponse.class, body); - } else { - response = builder.type(contentType).post(ClientResponse.class, serialize(body, contentType)); - } + response = builder.type(contentType).post(ClientResponse.class, serialize(body, contentType, formParams)); } else if ("PUT".equals(method)) { - if (encodedFormParams != null) { - response = builder.type(contentType).put(ClientResponse.class, encodedFormParams); - } else if(body == null) { - if(binaryBody == null) - response = builder.put(ClientResponse.class, null); - else - response = builder.type(contentType).put(ClientResponse.class, binaryBody); - } else { - response = builder.type(contentType).put(ClientResponse.class, serialize(body, contentType)); - } + response = builder.type(contentType).put(ClientResponse.class, serialize(body, contentType, formParams)); } else if ("DELETE".equals(method)) { - if (encodedFormParams != null) { - response = builder.type(contentType).delete(ClientResponse.class, encodedFormParams); - } else if(body == null) { - if(binaryBody == null) - response = builder.delete(ClientResponse.class); - else - response = builder.type(contentType).delete(ClientResponse.class, binaryBody); - } else { - response = builder.type(contentType).delete(ClientResponse.class, serialize(body, contentType)); - } + response = builder.type(contentType).delete(ClientResponse.class, serialize(body, contentType, formParams)); } else { throw new ApiException(500, "unknown method type " + method); } @@ -560,9 +530,9 @@ public class ApiClient { * @param authNames The authentications to apply * @return The response body in type of string */ - public T invokeAPI(String path, String method, List queryParams, Object body, byte[] binaryBody, Map headerParams, Map formParams, String accept, String contentType, String[] authNames, TypeRef returnType) throws ApiException { + public T invokeAPI(String path, String method, List queryParams, Object body, Map headerParams, Map formParams, String accept, String contentType, String[] authNames, TypeRef returnType) throws ApiException { - ClientResponse response = getAPIResponse(path, method, queryParams, body, binaryBody, headerParams, formParams, accept, contentType, authNames); + ClientResponse response = getAPIResponse(path, method, queryParams, body, headerParams, formParams, accept, contentType, authNames); statusCode = response.getStatusInfo().getStatusCode(); responseHeaders = response.getHeaders(); @@ -607,9 +577,9 @@ public class ApiClient { * @param authNames The authentications to apply * @return The response body in type of string */ - public byte[] invokeBinaryAPI(String path, String method, List queryParams, Object body, byte[] binaryBody, Map headerParams, Map formParams, String accept, String contentType, String[]authNames) throws ApiException { + public byte[] invokeBinaryAPI(String path, String method, List queryParams, Object body, Map headerParams, Map formParams, String accept, String contentType, String[]authNames) throws ApiException { - ClientResponse response = getAPIResponse(path, method, queryParams, body, binaryBody, headerParams, formParams, accept, contentType, authNames); + ClientResponse response = getAPIResponse(path, method, queryParams, body, headerParams, formParams, accept, contentType, authNames); if(response.getStatusInfo() == ClientResponse.Status.NO_CONTENT) { return null; diff --git a/modules/swagger-codegen/src/main/resources/Java/api.mustache b/modules/swagger-codegen/src/main/resources/Java/api.mustache index 5f617a253f14..fbdcc3d25e71 100644 --- a/modules/swagger-codegen/src/main/resources/Java/api.mustache +++ b/modules/swagger-codegen/src/main/resources/Java/api.mustache @@ -42,8 +42,7 @@ public class {{classname}} { {{/allParams}} * @return {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}} */ public {{#returnType}}{{{returnType}}} {{/returnType}}{{^returnType}}void {{/returnType}}{{operationId}}({{#allParams}}{{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) throws ApiException { - Object {{localVariablePrefix}}postBody = {{#bodyParam}}{{^isBinary}}{{paramName}}{{/isBinary}}{{#isBinary}}null{{/isBinary}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}}; - byte[] {{localVariablePrefix}}postBinaryBody = {{#bodyParam}}{{#isBinary}}{{paramName}}{{/isBinary}}{{^isBinary}}null{{/isBinary}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}}; + Object {{localVariablePrefix}}postBody = {{#bodyParam}}{{paramName}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}}; {{#allParams}}{{#required}} // verify the required parameter '{{paramName}}' is set if ({{paramName}} == null) { @@ -85,16 +84,16 @@ public class {{classname}} { {{#isResponseBinary}} byte[] {{localVariablePrefix}}response = null; - {{localVariablePrefix}}response = {{localVariablePrefix}}apiClient.invokeBinaryAPI({{localVariablePrefix}}path, "{{httpMethod}}", {{localVariablePrefix}}queryParams,{{localVariablePrefix}} postBody, {{localVariablePrefix}}postBinaryBody, {{localVariablePrefix}}headerParams, {{localVariablePrefix}}formParams, {{localVariablePrefix}}accept, {{localVariablePrefix}}contentType, {{localVariablePrefix}}authNames); + {{localVariablePrefix}}response = {{localVariablePrefix}}apiClient.invokeBinaryAPI({{localVariablePrefix}}path, "{{httpMethod}}", {{localVariablePrefix}}queryParams,{{localVariablePrefix}} postBody, {{localVariablePrefix}}headerParams, {{localVariablePrefix}}formParams, {{localVariablePrefix}}accept, {{localVariablePrefix}}contentType, {{localVariablePrefix}}authNames); return {{localVariablePrefix}}response; {{/isResponseBinary}} {{^isResponseBinary}} {{#returnType}} TypeRef {{localVariablePrefix}}returnType = new TypeRef<{{{returnType}}}>() {}; - return {{localVariablePrefix}}apiClient.invokeAPI({{localVariablePrefix}}path, "{{httpMethod}}", {{localVariablePrefix}}queryParams, {{localVariablePrefix}}postBody, {{localVariablePrefix}}postBinaryBody, {{localVariablePrefix}}headerParams, {{localVariablePrefix}}formParams, {{localVariablePrefix}}accept, {{localVariablePrefix}}contentType, {{localVariablePrefix}}authNames, {{localVariablePrefix}}returnType); + return {{localVariablePrefix}}apiClient.invokeAPI({{localVariablePrefix}}path, "{{httpMethod}}", {{localVariablePrefix}}queryParams, {{localVariablePrefix}}postBody, {{localVariablePrefix}}headerParams, {{localVariablePrefix}}formParams, {{localVariablePrefix}}accept, {{localVariablePrefix}}contentType, {{localVariablePrefix}}authNames, {{localVariablePrefix}}returnType); {{/returnType}}{{^returnType}} - {{localVariablePrefix}}apiClient.invokeAPI({{localVariablePrefix}}path, "{{httpMethod}}", {{localVariablePrefix}}queryParams, {{localVariablePrefix}}postBody, {{localVariablePrefix}}postBinaryBody, {{localVariablePrefix}}headerParams, {{localVariablePrefix}}formParams, {{localVariablePrefix}}accept, {{localVariablePrefix}}contentType, {{localVariablePrefix}}authNames, null); + {{localVariablePrefix}}apiClient.invokeAPI({{localVariablePrefix}}path, "{{httpMethod}}", {{localVariablePrefix}}queryParams, {{localVariablePrefix}}postBody, {{localVariablePrefix}}headerParams, {{localVariablePrefix}}formParams, {{localVariablePrefix}}accept, {{localVariablePrefix}}contentType, {{localVariablePrefix}}authNames, null); {{/returnType}} {{/isResponseBinary}} From ee3997772680721b8cd15e8968a66dae48c85140 Mon Sep 17 00:00:00 2001 From: evigeant Date: Wed, 2 Dec 2015 14:20:29 -0500 Subject: [PATCH 39/71] Let Jersey do the serialization and deserialization (including JSON) --- .../codegen/languages/JavaClientCodegen.java | 4 +- .../main/resources/Java/ApiClient.mustache | 141 ++++-------------- .../src/main/resources/Java/JSON.mustache | 64 -------- .../src/main/resources/Java/TypeRef.mustache | 26 ---- .../src/main/resources/Java/api.mustache | 15 +- .../src/main/resources/Java/pom.mustache | 5 + 6 files changed, 39 insertions(+), 216 deletions(-) delete mode 100644 modules/swagger-codegen/src/main/resources/Java/JSON.mustache delete mode 100644 modules/swagger-codegen/src/main/resources/Java/TypeRef.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 2f77a4178378..06326d1e4dd2 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 @@ -234,7 +234,6 @@ public class JavaClientCodegen extends DefaultCodegen implements CodegenConfig { if (!("feign".equals(getLibrary()) || "retrofit".equals(getLibrary()) || "retrofit2".equals(getLibrary()))) { supportingFiles.add(new SupportingFile("apiException.mustache", invokerFolder, "ApiException.java")); supportingFiles.add(new SupportingFile("Configuration.mustache", invokerFolder, "Configuration.java")); - supportingFiles.add(new SupportingFile("JSON.mustache", invokerFolder, "JSON.java")); supportingFiles.add(new SupportingFile("Pair.mustache", invokerFolder, "Pair.java")); supportingFiles.add(new SupportingFile("auth/Authentication.mustache", authFolder, "Authentication.java")); } @@ -244,6 +243,7 @@ public class JavaClientCodegen extends DefaultCodegen implements CodegenConfig { // the "okhttp-gson" library template requires "ApiCallback.mustache" for async call supportingFiles.add(new SupportingFile("ApiCallback.mustache", invokerFolder, "ApiCallback.java")); supportingFiles.add(new SupportingFile("ApiResponse.mustache", invokerFolder, "ApiResponse.java")); + supportingFiles.add(new SupportingFile("JSON.mustache", invokerFolder, "JSON.java")); supportingFiles.add(new SupportingFile("ProgressRequestBody.mustache", invokerFolder, "ProgressRequestBody.java")); supportingFiles.add(new SupportingFile("ProgressResponseBody.mustache", invokerFolder, "ProgressResponseBody.java")); // "build.sbt" is for development with SBT @@ -251,8 +251,6 @@ public class JavaClientCodegen extends DefaultCodegen implements CodegenConfig { } else if ("retrofit".equals(getLibrary()) || "retrofit2".equals(getLibrary())) { supportingFiles.add(new SupportingFile("auth/OAuthOkHttpClient.mustache", authFolder, "OAuthOkHttpClient.java")); supportingFiles.add(new SupportingFile("CollectionFormats.mustache", invokerFolder, "CollectionFormats.java")); - } else if (!"feign".equals(getLibrary())) { - supportingFiles.add(new SupportingFile("TypeRef.mustache", invokerFolder, "TypeRef.java")); } } diff --git a/modules/swagger-codegen/src/main/resources/Java/ApiClient.mustache b/modules/swagger-codegen/src/main/resources/Java/ApiClient.mustache index 679297f033f4..ef31058d5619 100644 --- a/modules/swagger-codegen/src/main/resources/Java/ApiClient.mustache +++ b/modules/swagger-codegen/src/main/resources/Java/ApiClient.mustache @@ -1,8 +1,13 @@ package {{invokerPackage}}; +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.datatype.joda.*; +import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider; + import com.sun.jersey.api.client.Client; import com.sun.jersey.api.client.ClientResponse; -import com.sun.jersey.api.client.config.ClientConfig; +import com.sun.jersey.api.client.GenericType; import com.sun.jersey.api.client.config.DefaultClientConfig; import com.sun.jersey.api.client.filter.LoggingFilter; import com.sun.jersey.api.client.WebResource.Builder; @@ -25,14 +30,11 @@ import java.util.TimeZone; import java.net.URLEncoder; -import java.io.IOException; import java.io.File; import java.io.UnsupportedEncodingException; -import java.io.DataInputStream; import java.text.DateFormat; import java.text.SimpleDateFormat; -import java.text.ParseException; import {{invokerPackage}}.auth.Authentication; import {{invokerPackage}}.auth.HttpBasicAuth; @@ -45,7 +47,7 @@ public class ApiClient { private Map defaultHeaderMap = new HashMap(); private boolean debugging = false; private String basePath = "{{basePath}}"; - private JSON json = new JSON(); + private ObjectMapper mapper; private Map authentications; @@ -55,6 +57,14 @@ public class ApiClient { private DateFormat dateFormat; public ApiClient() { + mapper = new ObjectMapper(); + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING); + mapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING); + mapper.registerModule(new JodaModule()); + // Use RFC3339 format for date and datetime. // See http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14 this.dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); @@ -62,7 +72,7 @@ public class ApiClient { // Use UTC as the default time zone. this.dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - this.json.setDateFormat((DateFormat) dateFormat.clone()); + this.mapper.setDateFormat((DateFormat) dateFormat.clone()); // Set default User-Agent. setUserAgent("Java-Swagger"); @@ -76,13 +86,6 @@ public class ApiClient { authentications = Collections.unmodifiableMap(authentications); } - /** - * Gets the JSON instance to do JSON serialization and deserialization. - */ - public JSON getJSON() { - return json; - } - public String getBasePath() { return basePath; } @@ -237,7 +240,7 @@ public class ApiClient { public ApiClient setDateFormat(DateFormat dateFormat) { this.dateFormat = dateFormat; // also set the date format for model (de)serialization with Date properties - this.json.setDateFormat((DateFormat) dateFormat.clone()); + this.mapper.setDateFormat((DateFormat) dateFormat.clone()); return this; } @@ -269,7 +272,7 @@ public class ApiClient { return formatDate((Date) param); } else if (param instanceof Collection) { StringBuilder b = new StringBuilder(); - for(Object o : (Collection)param) { + for(Object o : (Collection)param) { if(b.length() > 0) { b.append(","); } @@ -290,9 +293,9 @@ public class ApiClient { // preconditions if (name == null || name.isEmpty() || value == null) return params; - Collection valueCollection = null; - if (value instanceof Collection) { - valueCollection = (Collection) value; + Collection valueCollection = null; + if (value instanceof Collection) { + valueCollection = (Collection) value; } else { params.add(new Pair(name, parameterToString(value))); return params; @@ -406,9 +409,7 @@ public class ApiClient { * Content-Type (only JSON is supported for now). */ public Object serialize(Object obj, String contentType, Map formParams) throws ApiException { - if (isJsonMime(contentType)) { - return json.serialize(obj); - } else if (contentType.startsWith("multipart/form-data")) { + if (contentType.startsWith("multipart/form-data")) { FormDataMultiPart mp = new FormDataMultiPart(); for (Entry param: formParams.entrySet()) { if (param.getValue() instanceof File) { @@ -424,38 +425,6 @@ public class ApiClient { } else { // We let Jersey attempt to serialize the body return obj; - //throw new ApiException(400, "can not serialize object into Content-Type: " + contentType); - } - } - - /** - * Deserialize response body to Java object according to the Content-Type. - */ - public T deserialize(ClientResponse response, TypeRef returnType) throws ApiException { - String contentType = null; - List contentTypes = response.getHeaders().get("Content-Type"); - if (contentTypes != null && !contentTypes.isEmpty()) - contentType = contentTypes.get(0); - if (contentType == null) - throw new ApiException(500, "missing Content-Type in response"); - - String body; - if (response.hasEntity()) - body = (String) response.getEntity(String.class); - else - body = ""; - - if (isJsonMime(contentType)) { - return json.deserialize(body, returnType); - } else if (returnType.getType().equals(String.class)) { - // Expecting string, return the raw response body. - return (T) body; - } else { - throw new ApiException( - 500, - "Content type \"" + contentType + "\" is not supported for type: " - + returnType.getType() - ); } } @@ -522,7 +491,6 @@ public class ApiClient { * @param method The request method, one of "GET", "POST", "PUT", and "DELETE" * @param queryParams The query parameters * @param body The request body object - if it is not binary, otherwise null - * @param binaryBody The request body object - if it is binary, otherwise null * @param headerParams The header parameters * @param formParams The form parameters * @param accept The request's Accept header @@ -530,7 +498,7 @@ public class ApiClient { * @param authNames The authentications to apply * @return The response body in type of string */ - public T invokeAPI(String path, String method, List queryParams, Object body, Map headerParams, Map formParams, String accept, String contentType, String[] authNames, TypeRef returnType) throws ApiException { + public T invokeAPI(String path, String method, List queryParams, Object body, Map headerParams, Map formParams, String accept, String contentType, String[] authNames, GenericType returnType) throws ApiException { ClientResponse response = getAPIResponse(path, method, queryParams, body, headerParams, formParams, accept, contentType, authNames); @@ -543,13 +511,13 @@ public class ApiClient { if (returnType == null) return null; else - return deserialize(response, returnType); + return response.getEntity(returnType); } else { String message = "error"; String respBody = null; if (response.hasEntity()) { try { - respBody = String.valueOf(response.getEntity(String.class)); + respBody = response.getEntity(String.class); message = respBody; } catch (RuntimeException e) { // e.printStackTrace(); @@ -562,58 +530,6 @@ public class ApiClient { respBody); } } - /** - * Invoke API by sending HTTP request with the given options - return binary result - * - * @param path The sub-path of the HTTP URL - * @param method The request method, one of "GET", "POST", "PUT", and "DELETE" - * @param queryParams The query parameters - * @param body The request body object - if it is not binary, otherwise null - * @param binaryBody The request body object - if it is binary, otherwise null - * @param headerParams The header parameters - * @param formParams The form parameters - * @param accept The request's Accept header - * @param contentType The request's Content-Type header - * @param authNames The authentications to apply - * @return The response body in type of string - */ - public byte[] invokeBinaryAPI(String path, String method, List queryParams, Object body, Map headerParams, Map formParams, String accept, String contentType, String[]authNames) throws ApiException { - - ClientResponse response = getAPIResponse(path, method, queryParams, body, headerParams, formParams, accept, contentType, authNames); - - if(response.getStatusInfo() == ClientResponse.Status.NO_CONTENT) { - return null; - } - else if(response.getStatusInfo().getFamily() == Family.SUCCESSFUL) { - if(response.hasEntity()) { - DataInputStream stream = new DataInputStream(response.getEntityInputStream()); - byte[] data = new byte[response.getLength()]; - try { - stream.readFully(data); - } catch (IOException ex) { - throw new ApiException(500, "Error obtaining binary response data"); - } - return data; - } - else { - return new byte[0]; - } - } - else { - String message = "error"; - if(response.hasEntity()) { - try{ - message = String.valueOf(response.getEntity(String.class)); - } - catch (RuntimeException e) { - // e.printStackTrace(); - } - } - throw new ApiException( - response.getStatusInfo().getStatusCode(), - message); - } - } /** * Update query and header parameters based on authentication settings. @@ -635,7 +551,6 @@ public class ApiClient { StringBuilder formParamBuilder = new StringBuilder(); for (Entry param : formParams.entrySet()) { - String keyStr = param.getKey(); String valueStr = parameterToString(param.getValue()); try { formParamBuilder.append(URLEncoder.encode(param.getKey(), "utf8")) @@ -660,7 +575,11 @@ public class ApiClient { */ private Client getClient() { if(!hostMap.containsKey(basePath)) { - Client client = Client.create(); + // Add the JSON serialization support to Jersey + JacksonJsonProvider jsonProvider = new JacksonJsonProvider(mapper); + DefaultClientConfig conf = new DefaultClientConfig(); + conf.getSingletons().add(jsonProvider); + Client client = Client.create(conf); if (debugging) client.addFilter(new LoggingFilter()); hostMap.put(basePath, client); diff --git a/modules/swagger-codegen/src/main/resources/Java/JSON.mustache b/modules/swagger-codegen/src/main/resources/Java/JSON.mustache deleted file mode 100644 index 54faed8dcb38..000000000000 --- a/modules/swagger-codegen/src/main/resources/Java/JSON.mustache +++ /dev/null @@ -1,64 +0,0 @@ -package {{invokerPackage}}; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.*; -import com.fasterxml.jackson.datatype.joda.*; - -import java.text.DateFormat; - -import java.io.IOException; - -{{>generatedAnnotation}} -public class JSON { - private ObjectMapper mapper; - - public JSON() { - mapper = new ObjectMapper(); - mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); - mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); - mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING); - mapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING); - mapper.registerModule(new JodaModule()); - } - - /** - * Set the date format for JSON (de)serialization with Date properties. - */ - public void setDateFormat(DateFormat dateFormat) { - mapper.setDateFormat(dateFormat); - } - - /** - * Serialize the given Java object into JSON string. - */ - public String serialize(Object obj) throws ApiException { - try { - if (obj != null) - return mapper.writeValueAsString(obj); - else - return null; - } catch (Exception e) { - throw new ApiException(400, e.getMessage()); - } - } - - /** - * Deserialize the given JSON string to Java object. - * - * @param body The JSON string - * @param returnType The type to deserialize inot - * @return The deserialized Java object - */ - public T deserialize(String body, TypeRef returnType) throws ApiException { - JavaType javaType = mapper.constructType(returnType.getType()); - try { - return mapper.readValue(body, javaType); - } catch (IOException e) { - if (returnType.getType().equals(String.class)) - return (T) body; - else - throw new ApiException(500, e.getMessage(), null, body); - } - } -} diff --git a/modules/swagger-codegen/src/main/resources/Java/TypeRef.mustache b/modules/swagger-codegen/src/main/resources/Java/TypeRef.mustache deleted file mode 100644 index 9e9ba5f88956..000000000000 --- a/modules/swagger-codegen/src/main/resources/Java/TypeRef.mustache +++ /dev/null @@ -1,26 +0,0 @@ -package {{invokerPackage}}; - -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; - -{{>generatedAnnotation}} -public class TypeRef { - private final Type type; - - public TypeRef() { - this.type = getGenericType(getClass()); - } - - private static Type getGenericType(Class klass) { - Type superclass = klass.getGenericSuperclass(); - if (superclass instanceof Class) { - throw new RuntimeException("No type parameter provided"); - } - ParameterizedType parameterized = (ParameterizedType) superclass; - return parameterized.getActualTypeArguments()[0]; - } - - public Type getType() { - return type; - } -} diff --git a/modules/swagger-codegen/src/main/resources/Java/api.mustache b/modules/swagger-codegen/src/main/resources/Java/api.mustache index fbdcc3d25e71..fc441df954a7 100644 --- a/modules/swagger-codegen/src/main/resources/Java/api.mustache +++ b/modules/swagger-codegen/src/main/resources/Java/api.mustache @@ -1,10 +1,11 @@ package {{package}}; +import com.sun.jersey.api.client.GenericType; + import {{invokerPackage}}.ApiException; import {{invokerPackage}}.ApiClient; import {{invokerPackage}}.Configuration; import {{invokerPackage}}.Pair; -import {{invokerPackage}}.TypeRef; {{#imports}}import {{import}}; {{/imports}} @@ -82,22 +83,12 @@ public class {{classname}} { String[] {{localVariablePrefix}}authNames = new String[] { {{#authMethods}}"{{name}}"{{#hasMore}}, {{/hasMore}}{{/authMethods}} }; - {{#isResponseBinary}} - byte[] {{localVariablePrefix}}response = null; - {{localVariablePrefix}}response = {{localVariablePrefix}}apiClient.invokeBinaryAPI({{localVariablePrefix}}path, "{{httpMethod}}", {{localVariablePrefix}}queryParams,{{localVariablePrefix}} postBody, {{localVariablePrefix}}headerParams, {{localVariablePrefix}}formParams, {{localVariablePrefix}}accept, {{localVariablePrefix}}contentType, {{localVariablePrefix}}authNames); - return {{localVariablePrefix}}response; - {{/isResponseBinary}} - - {{^isResponseBinary}} {{#returnType}} - TypeRef {{localVariablePrefix}}returnType = new TypeRef<{{{returnType}}}>() {}; + GenericType<{{{returnType}}}> {{localVariablePrefix}}returnType = new GenericType<{{{returnType}}}>() {}; return {{localVariablePrefix}}apiClient.invokeAPI({{localVariablePrefix}}path, "{{httpMethod}}", {{localVariablePrefix}}queryParams, {{localVariablePrefix}}postBody, {{localVariablePrefix}}headerParams, {{localVariablePrefix}}formParams, {{localVariablePrefix}}accept, {{localVariablePrefix}}contentType, {{localVariablePrefix}}authNames, {{localVariablePrefix}}returnType); {{/returnType}}{{^returnType}} {{localVariablePrefix}}apiClient.invokeAPI({{localVariablePrefix}}path, "{{httpMethod}}", {{localVariablePrefix}}queryParams, {{localVariablePrefix}}postBody, {{localVariablePrefix}}headerParams, {{localVariablePrefix}}formParams, {{localVariablePrefix}}accept, {{localVariablePrefix}}contentType, {{localVariablePrefix}}authNames, null); {{/returnType}} - {{/isResponseBinary}} - - } {{/operation}} } diff --git a/modules/swagger-codegen/src/main/resources/Java/pom.mustache b/modules/swagger-codegen/src/main/resources/Java/pom.mustache index c5bfbc65b746..f2c20a96740b 100644 --- a/modules/swagger-codegen/src/main/resources/Java/pom.mustache +++ b/modules/swagger-codegen/src/main/resources/Java/pom.mustache @@ -137,6 +137,11 @@ jackson-databind ${jackson-version} + + com.fasterxml.jackson.jaxrs + jackson-jaxrs-json-provider + ${jackson-version} + com.fasterxml.jackson.datatype jackson-datatype-joda From d51746d7fa5426bda048b2fdacd6987c3f45668e Mon Sep 17 00:00:00 2001 From: evigeant Date: Thu, 3 Dec 2015 16:08:10 -0500 Subject: [PATCH 40/71] Updated PetStore sample for Java client (default) --- samples/client/petstore/java/default/pom.xml | 5 + .../java/io/swagger/client/ApiClient.java | 217 +++++------------- .../src/main/java/io/swagger/client/JSON.java | 64 ------ .../main/java/io/swagger/client/TypeRef.java | 26 --- .../java/io/swagger/client/api/PetApi.java | 99 ++------ .../java/io/swagger/client/api/StoreApi.java | 55 ++--- .../java/io/swagger/client/api/UserApi.java | 97 ++------ .../test/java/io/swagger/client/JSONTest.java | 52 ----- 8 files changed, 115 insertions(+), 500 deletions(-) delete mode 100644 samples/client/petstore/java/default/src/main/java/io/swagger/client/JSON.java delete mode 100644 samples/client/petstore/java/default/src/main/java/io/swagger/client/TypeRef.java delete mode 100644 samples/client/petstore/java/default/src/test/java/io/swagger/client/JSONTest.java diff --git a/samples/client/petstore/java/default/pom.xml b/samples/client/petstore/java/default/pom.xml index 8a939b9dc34a..e35e30af5833 100644 --- a/samples/client/petstore/java/default/pom.xml +++ b/samples/client/petstore/java/default/pom.xml @@ -137,6 +137,11 @@ jackson-databind ${jackson-version} + + com.fasterxml.jackson.jaxrs + jackson-jaxrs-json-provider + ${jackson-version} + com.fasterxml.jackson.datatype jackson-datatype-joda diff --git a/samples/client/petstore/java/default/src/main/java/io/swagger/client/ApiClient.java b/samples/client/petstore/java/default/src/main/java/io/swagger/client/ApiClient.java index 3d40225c78f6..f34125eaa44a 100644 --- a/samples/client/petstore/java/default/src/main/java/io/swagger/client/ApiClient.java +++ b/samples/client/petstore/java/default/src/main/java/io/swagger/client/ApiClient.java @@ -1,8 +1,13 @@ package io.swagger.client; +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.datatype.joda.*; +import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider; + import com.sun.jersey.api.client.Client; import com.sun.jersey.api.client.ClientResponse; -import com.sun.jersey.api.client.config.ClientConfig; +import com.sun.jersey.api.client.GenericType; import com.sun.jersey.api.client.config.DefaultClientConfig; import com.sun.jersey.api.client.filter.LoggingFilter; import com.sun.jersey.api.client.WebResource.Builder; @@ -25,27 +30,24 @@ import java.util.TimeZone; import java.net.URLEncoder; -import java.io.IOException; import java.io.File; import java.io.UnsupportedEncodingException; -import java.io.DataInputStream; import java.text.DateFormat; import java.text.SimpleDateFormat; -import java.text.ParseException; import io.swagger.client.auth.Authentication; import io.swagger.client.auth.HttpBasicAuth; import io.swagger.client.auth.ApiKeyAuth; import io.swagger.client.auth.OAuth; -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-09T16:17:57.986+08:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-09T22:51:50.471-05:00") public class ApiClient { private Map hostMap = new HashMap(); private Map defaultHeaderMap = new HashMap(); private boolean debugging = false; private String basePath = "http://petstore.swagger.io/v2"; - private JSON json = new JSON(); + private ObjectMapper mapper; private Map authentications; @@ -55,6 +57,14 @@ public class ApiClient { private DateFormat dateFormat; public ApiClient() { + mapper = new ObjectMapper(); + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING); + mapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING); + mapper.registerModule(new JodaModule()); + // Use RFC3339 format for date and datetime. // See http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14 this.dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); @@ -62,7 +72,7 @@ public class ApiClient { // Use UTC as the default time zone. this.dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - this.json.setDateFormat((DateFormat) dateFormat.clone()); + this.mapper.setDateFormat((DateFormat) dateFormat.clone()); // Set default User-Agent. setUserAgent("Java-Swagger"); @@ -75,13 +85,6 @@ public class ApiClient { authentications = Collections.unmodifiableMap(authentications); } - /** - * Gets the JSON instance to do JSON serialization and deserialization. - */ - public JSON getJSON() { - return json; - } - public String getBasePath() { return basePath; } @@ -236,7 +239,7 @@ public class ApiClient { public ApiClient setDateFormat(DateFormat dateFormat) { this.dateFormat = dateFormat; // also set the date format for model (de)serialization with Date properties - this.json.setDateFormat((DateFormat) dateFormat.clone()); + this.mapper.setDateFormat((DateFormat) dateFormat.clone()); return this; } @@ -268,7 +271,7 @@ public class ApiClient { return formatDate((Date) param); } else if (param instanceof Collection) { StringBuilder b = new StringBuilder(); - for(Object o : (Collection)param) { + for(Object o : (Collection)param) { if(b.length() > 0) { b.append(","); } @@ -289,9 +292,9 @@ public class ApiClient { // preconditions if (name == null || name.isEmpty() || value == null) return params; - Collection valueCollection = null; - if (value instanceof Collection) { - valueCollection = (Collection) value; + Collection valueCollection = null; + if (value instanceof Collection) { + valueCollection = (Collection) value; } else { params.add(new Pair(name, parameterToString(value))); return params; @@ -404,49 +407,30 @@ public class ApiClient { * Serialize the given Java object into string according the given * Content-Type (only JSON is supported for now). */ - public String serialize(Object obj, String contentType) throws ApiException { - if (isJsonMime(contentType)) { - return json.serialize(obj); + public Object serialize(Object obj, String contentType, Map formParams) throws ApiException { + if (contentType.startsWith("multipart/form-data")) { + FormDataMultiPart mp = new FormDataMultiPart(); + for (Entry param: formParams.entrySet()) { + if (param.getValue() instanceof File) { + File file = (File) param.getValue(); + mp.bodyPart(new FileDataBodyPart(param.getKey(), file, MediaType.MULTIPART_FORM_DATA_TYPE)); + } else { + mp.field(param.getKey(), parameterToString(param.getValue()), MediaType.MULTIPART_FORM_DATA_TYPE); + } + } + return mp; + } else if (contentType.startsWith("application/x-www-form-urlencoded")) { + return this.getXWWWFormUrlencodedParams(formParams); } else { - throw new ApiException(400, "can not serialize object into Content-Type: " + contentType); + // We let Jersey attempt to serialize the body + return obj; } } - /** - * Deserialize response body to Java object according to the Content-Type. - */ - public T deserialize(ClientResponse response, TypeRef returnType) throws ApiException { - String contentType = null; - List contentTypes = response.getHeaders().get("Content-Type"); - if (contentTypes != null && !contentTypes.isEmpty()) - contentType = contentTypes.get(0); - if (contentType == null) - throw new ApiException(500, "missing Content-Type in response"); + private ClientResponse getAPIResponse(String path, String method, List queryParams, Object body, Map headerParams, Map formParams, String accept, String contentType, String[] authNames) throws ApiException { - String body; - if (response.hasEntity()) - body = (String) response.getEntity(String.class); - else - body = ""; - - if (isJsonMime(contentType)) { - return json.deserialize(body, returnType); - } else if (returnType.getType().equals(String.class)) { - // Expecting string, return the raw response body. - return (T) body; - } else { - throw new ApiException( - 500, - "Content type \"" + contentType + "\" is not supported for type: " - + returnType.getType() - ); - } - } - - private ClientResponse getAPIResponse(String path, String method, List queryParams, Object body, byte[] binaryBody, Map headerParams, Map formParams, String accept, String contentType, String[] authNames) throws ApiException { - - if (body != null && binaryBody != null){ - throw new ApiException(500, "either body or binaryBody must be null"); + if (body != null && !formParams.isEmpty()){ + throw new ApiException(500, "Cannot have body and form params"); } updateParamsForAuth(authNames, queryParams, headerParams); @@ -483,61 +467,16 @@ public class ApiClient { } } - String encodedFormParams = null; - if (contentType.startsWith("multipart/form-data")) { - FormDataMultiPart mp = new FormDataMultiPart(); - for (Entry param: formParams.entrySet()) { - if (param.getValue() instanceof File) { - File file = (File) param.getValue(); - mp.bodyPart(new FileDataBodyPart(param.getKey(), file, MediaType.MULTIPART_FORM_DATA_TYPE)); - } else { - mp.field(param.getKey(), parameterToString(param.getValue()), MediaType.MULTIPART_FORM_DATA_TYPE); - } - } - body = mp; - } else if (contentType.startsWith("application/x-www-form-urlencoded")) { - encodedFormParams = this.getXWWWFormUrlencodedParams(formParams); - } - ClientResponse response = null; if ("GET".equals(method)) { response = (ClientResponse) builder.get(ClientResponse.class); } else if ("POST".equals(method)) { - if (encodedFormParams != null) { - response = builder.type(contentType).post(ClientResponse.class, encodedFormParams); - } else if (body == null) { - if(binaryBody == null) - response = builder.post(ClientResponse.class, null); - else - response = builder.type(contentType).post(ClientResponse.class, binaryBody); - } else if (body instanceof FormDataMultiPart) { - response = builder.type(contentType).post(ClientResponse.class, body); - } else { - response = builder.type(contentType).post(ClientResponse.class, serialize(body, contentType)); - } + response = builder.type(contentType).post(ClientResponse.class, serialize(body, contentType, formParams)); } else if ("PUT".equals(method)) { - if (encodedFormParams != null) { - response = builder.type(contentType).put(ClientResponse.class, encodedFormParams); - } else if(body == null) { - if(binaryBody == null) - response = builder.put(ClientResponse.class, null); - else - response = builder.type(contentType).put(ClientResponse.class, binaryBody); - } else { - response = builder.type(contentType).put(ClientResponse.class, serialize(body, contentType)); - } + response = builder.type(contentType).put(ClientResponse.class, serialize(body, contentType, formParams)); } else if ("DELETE".equals(method)) { - if (encodedFormParams != null) { - response = builder.type(contentType).delete(ClientResponse.class, encodedFormParams); - } else if(body == null) { - if(binaryBody == null) - response = builder.delete(ClientResponse.class); - else - response = builder.type(contentType).delete(ClientResponse.class, binaryBody); - } else { - response = builder.type(contentType).delete(ClientResponse.class, serialize(body, contentType)); - } + response = builder.type(contentType).delete(ClientResponse.class, serialize(body, contentType, formParams)); } else { throw new ApiException(500, "unknown method type " + method); } @@ -551,7 +490,6 @@ public class ApiClient { * @param method The request method, one of "GET", "POST", "PUT", and "DELETE" * @param queryParams The query parameters * @param body The request body object - if it is not binary, otherwise null - * @param binaryBody The request body object - if it is binary, otherwise null * @param headerParams The header parameters * @param formParams The form parameters * @param accept The request's Accept header @@ -559,9 +497,9 @@ public class ApiClient { * @param authNames The authentications to apply * @return The response body in type of string */ - public T invokeAPI(String path, String method, List queryParams, Object body, byte[] binaryBody, Map headerParams, Map formParams, String accept, String contentType, String[] authNames, TypeRef returnType) throws ApiException { + public T invokeAPI(String path, String method, List queryParams, Object body, Map headerParams, Map formParams, String accept, String contentType, String[] authNames, GenericType returnType) throws ApiException { - ClientResponse response = getAPIResponse(path, method, queryParams, body, binaryBody, headerParams, formParams, accept, contentType, authNames); + ClientResponse response = getAPIResponse(path, method, queryParams, body, headerParams, formParams, accept, contentType, authNames); statusCode = response.getStatusInfo().getStatusCode(); responseHeaders = response.getHeaders(); @@ -572,13 +510,13 @@ public class ApiClient { if (returnType == null) return null; else - return deserialize(response, returnType); + return response.getEntity(returnType); } else { String message = "error"; String respBody = null; if (response.hasEntity()) { try { - respBody = String.valueOf(response.getEntity(String.class)); + respBody = response.getEntity(String.class); message = respBody; } catch (RuntimeException e) { // e.printStackTrace(); @@ -591,58 +529,6 @@ public class ApiClient { respBody); } } - /** - * Invoke API by sending HTTP request with the given options - return binary result - * - * @param path The sub-path of the HTTP URL - * @param method The request method, one of "GET", "POST", "PUT", and "DELETE" - * @param queryParams The query parameters - * @param body The request body object - if it is not binary, otherwise null - * @param binaryBody The request body object - if it is binary, otherwise null - * @param headerParams The header parameters - * @param formParams The form parameters - * @param accept The request's Accept header - * @param contentType The request's Content-Type header - * @param authNames The authentications to apply - * @return The response body in type of string - */ - public byte[] invokeBinaryAPI(String path, String method, List queryParams, Object body, byte[] binaryBody, Map headerParams, Map formParams, String accept, String contentType, String[]authNames) throws ApiException { - - ClientResponse response = getAPIResponse(path, method, queryParams, body, binaryBody, headerParams, formParams, accept, contentType, authNames); - - if(response.getStatusInfo() == ClientResponse.Status.NO_CONTENT) { - return null; - } - else if(response.getStatusInfo().getFamily() == Family.SUCCESSFUL) { - if(response.hasEntity()) { - DataInputStream stream = new DataInputStream(response.getEntityInputStream()); - byte[] data = new byte[response.getLength()]; - try { - stream.readFully(data); - } catch (IOException ex) { - throw new ApiException(500, "Error obtaining binary response data"); - } - return data; - } - else { - return new byte[0]; - } - } - else { - String message = "error"; - if(response.hasEntity()) { - try{ - message = String.valueOf(response.getEntity(String.class)); - } - catch (RuntimeException e) { - // e.printStackTrace(); - } - } - throw new ApiException( - response.getStatusInfo().getStatusCode(), - message); - } - } /** * Update query and header parameters based on authentication settings. @@ -664,7 +550,6 @@ public class ApiClient { StringBuilder formParamBuilder = new StringBuilder(); for (Entry param : formParams.entrySet()) { - String keyStr = param.getKey(); String valueStr = parameterToString(param.getValue()); try { formParamBuilder.append(URLEncoder.encode(param.getKey(), "utf8")) @@ -689,7 +574,11 @@ public class ApiClient { */ private Client getClient() { if(!hostMap.containsKey(basePath)) { - Client client = Client.create(); + // Add the JSON serialization support to Jersey + JacksonJsonProvider jsonProvider = new JacksonJsonProvider(mapper); + DefaultClientConfig conf = new DefaultClientConfig(); + conf.getSingletons().add(jsonProvider); + Client client = Client.create(conf); if (debugging) client.addFilter(new LoggingFilter()); hostMap.put(basePath, client); diff --git a/samples/client/petstore/java/default/src/main/java/io/swagger/client/JSON.java b/samples/client/petstore/java/default/src/main/java/io/swagger/client/JSON.java deleted file mode 100644 index e26cf13bee50..000000000000 --- a/samples/client/petstore/java/default/src/main/java/io/swagger/client/JSON.java +++ /dev/null @@ -1,64 +0,0 @@ -package io.swagger.client; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.*; -import com.fasterxml.jackson.datatype.joda.*; - -import java.text.DateFormat; - -import java.io.IOException; - -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-11-29T00:18:25.953+08:00") -public class JSON { - private ObjectMapper mapper; - - public JSON() { - mapper = new ObjectMapper(); - mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); - mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); - mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING); - mapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING); - mapper.registerModule(new JodaModule()); - } - - /** - * Set the date format for JSON (de)serialization with Date properties. - */ - public void setDateFormat(DateFormat dateFormat) { - mapper.setDateFormat(dateFormat); - } - - /** - * Serialize the given Java object into JSON string. - */ - public String serialize(Object obj) throws ApiException { - try { - if (obj != null) - return mapper.writeValueAsString(obj); - else - return null; - } catch (Exception e) { - throw new ApiException(400, e.getMessage()); - } - } - - /** - * Deserialize the given JSON string to Java object. - * - * @param body The JSON string - * @param returnType The type to deserialize inot - * @return The deserialized Java object - */ - public T deserialize(String body, TypeRef returnType) throws ApiException { - JavaType javaType = mapper.constructType(returnType.getType()); - try { - return mapper.readValue(body, javaType); - } catch (IOException e) { - if (returnType.getType().equals(String.class)) - return (T) body; - else - throw new ApiException(500, e.getMessage(), null, body); - } - } -} diff --git a/samples/client/petstore/java/default/src/main/java/io/swagger/client/TypeRef.java b/samples/client/petstore/java/default/src/main/java/io/swagger/client/TypeRef.java deleted file mode 100644 index 41677e9d5570..000000000000 --- a/samples/client/petstore/java/default/src/main/java/io/swagger/client/TypeRef.java +++ /dev/null @@ -1,26 +0,0 @@ -package io.swagger.client; - -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; - -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-11-29T00:18:25.953+08:00") -public class TypeRef { - private final Type type; - - public TypeRef() { - this.type = getGenericType(getClass()); - } - - private static Type getGenericType(Class klass) { - Type superclass = klass.getGenericSuperclass(); - if (superclass instanceof Class) { - throw new RuntimeException("No type parameter provided"); - } - ParameterizedType parameterized = (ParameterizedType) superclass; - return parameterized.getActualTypeArguments()[0]; - } - - public Type getType() { - return type; - } -} diff --git a/samples/client/petstore/java/default/src/main/java/io/swagger/client/api/PetApi.java b/samples/client/petstore/java/default/src/main/java/io/swagger/client/api/PetApi.java index 080d4aa1dab9..9f07449e6f89 100644 --- a/samples/client/petstore/java/default/src/main/java/io/swagger/client/api/PetApi.java +++ b/samples/client/petstore/java/default/src/main/java/io/swagger/client/api/PetApi.java @@ -1,17 +1,18 @@ package io.swagger.client.api; +import com.sun.jersey.api.client.GenericType; + import io.swagger.client.ApiException; import io.swagger.client.ApiClient; import io.swagger.client.Configuration; import io.swagger.client.Pair; -import io.swagger.client.TypeRef; import io.swagger.client.model.Pet; import java.io.File; import java.util.*; -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-11-29T00:18:25.953+08:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-09T22:51:50.471-05:00") public class PetApi { private ApiClient apiClient; @@ -38,9 +39,8 @@ public class PetApi { * @param body Pet object that needs to be added to the store * @return void */ - public void updatePet (Pet body) throws ApiException { + public void updatePet(Pet body) throws ApiException { Object postBody = body; - byte[] postBinaryBody = null; // create path and map variables String path = "/pet".replaceAll("\\{format\\}","json"); @@ -69,14 +69,8 @@ public class PetApi { String[] authNames = new String[] { "petstore_auth" }; - + apiClient.invokeAPI(path, "PUT", queryParams, postBody, headerParams, formParams, accept, contentType, authNames, null); - - apiClient.invokeAPI(path, "PUT", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, null); - - - - } /** @@ -85,9 +79,8 @@ public class PetApi { * @param body Pet object that needs to be added to the store * @return void */ - public void addPet (Pet body) throws ApiException { + public void addPet(Pet body) throws ApiException { Object postBody = body; - byte[] postBinaryBody = null; // create path and map variables String path = "/pet".replaceAll("\\{format\\}","json"); @@ -116,14 +109,8 @@ public class PetApi { String[] authNames = new String[] { "petstore_auth" }; - + apiClient.invokeAPI(path, "POST", queryParams, postBody, headerParams, formParams, accept, contentType, authNames, null); - - apiClient.invokeAPI(path, "POST", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, null); - - - - } /** @@ -132,9 +119,8 @@ public class PetApi { * @param status Status values that need to be considered for filter * @return List */ - public List findPetsByStatus (List status) throws ApiException { + public List findPetsByStatus(List status) throws ApiException { Object postBody = null; - byte[] postBinaryBody = null; // create path and map variables String path = "/pet/findByStatus".replaceAll("\\{format\\}","json"); @@ -165,15 +151,9 @@ public class PetApi { String[] authNames = new String[] { "petstore_auth" }; - + GenericType> returnType = new GenericType>() {}; + return apiClient.invokeAPI(path, "GET", queryParams, postBody, headerParams, formParams, accept, contentType, authNames, returnType); - - TypeRef returnType = new TypeRef>() {}; - return apiClient.invokeAPI(path, "GET", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, returnType); - - - - } /** @@ -182,9 +162,8 @@ public class PetApi { * @param tags Tags to filter by * @return List */ - public List findPetsByTags (List tags) throws ApiException { + public List findPetsByTags(List tags) throws ApiException { Object postBody = null; - byte[] postBinaryBody = null; // create path and map variables String path = "/pet/findByTags".replaceAll("\\{format\\}","json"); @@ -215,15 +194,9 @@ public class PetApi { String[] authNames = new String[] { "petstore_auth" }; - + GenericType> returnType = new GenericType>() {}; + return apiClient.invokeAPI(path, "GET", queryParams, postBody, headerParams, formParams, accept, contentType, authNames, returnType); - - TypeRef returnType = new TypeRef>() {}; - return apiClient.invokeAPI(path, "GET", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, returnType); - - - - } /** @@ -232,9 +205,8 @@ public class PetApi { * @param petId ID of pet that needs to be fetched * @return Pet */ - public Pet getPetById (Long petId) throws ApiException { + public Pet getPetById(Long petId) throws ApiException { Object postBody = null; - byte[] postBinaryBody = null; // verify the required parameter 'petId' is set if (petId == null) { @@ -269,15 +241,9 @@ public class PetApi { String[] authNames = new String[] { "api_key" }; - + GenericType returnType = new GenericType() {}; + return apiClient.invokeAPI(path, "GET", queryParams, postBody, headerParams, formParams, accept, contentType, authNames, returnType); - - TypeRef returnType = new TypeRef() {}; - return apiClient.invokeAPI(path, "GET", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, returnType); - - - - } /** @@ -288,9 +254,8 @@ public class PetApi { * @param status Updated status of the pet * @return void */ - public void updatePetWithForm (String petId, String name, String status) throws ApiException { + public void updatePetWithForm(String petId, String name, String status) throws ApiException { Object postBody = null; - byte[] postBinaryBody = null; // verify the required parameter 'petId' is set if (petId == null) { @@ -329,14 +294,8 @@ public class PetApi { String[] authNames = new String[] { "petstore_auth" }; - + apiClient.invokeAPI(path, "POST", queryParams, postBody, headerParams, formParams, accept, contentType, authNames, null); - - apiClient.invokeAPI(path, "POST", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, null); - - - - } /** @@ -346,9 +305,8 @@ public class PetApi { * @param apiKey * @return void */ - public void deletePet (Long petId, String apiKey) throws ApiException { + public void deletePet(Long petId, String apiKey) throws ApiException { Object postBody = null; - byte[] postBinaryBody = null; // verify the required parameter 'petId' is set if (petId == null) { @@ -385,14 +343,8 @@ public class PetApi { String[] authNames = new String[] { "petstore_auth" }; - + apiClient.invokeAPI(path, "DELETE", queryParams, postBody, headerParams, formParams, accept, contentType, authNames, null); - - apiClient.invokeAPI(path, "DELETE", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, null); - - - - } /** @@ -403,9 +355,8 @@ public class PetApi { * @param file file to upload * @return void */ - public void uploadFile (Long petId, String additionalMetadata, File file) throws ApiException { + public void uploadFile(Long petId, String additionalMetadata, File file) throws ApiException { Object postBody = null; - byte[] postBinaryBody = null; // verify the required parameter 'petId' is set if (petId == null) { @@ -444,14 +395,8 @@ public class PetApi { String[] authNames = new String[] { "petstore_auth" }; - + apiClient.invokeAPI(path, "POST", queryParams, postBody, headerParams, formParams, accept, contentType, authNames, null); - - apiClient.invokeAPI(path, "POST", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, null); - - - - } } diff --git a/samples/client/petstore/java/default/src/main/java/io/swagger/client/api/StoreApi.java b/samples/client/petstore/java/default/src/main/java/io/swagger/client/api/StoreApi.java index b7ce75e5532e..f6f3b84708e7 100644 --- a/samples/client/petstore/java/default/src/main/java/io/swagger/client/api/StoreApi.java +++ b/samples/client/petstore/java/default/src/main/java/io/swagger/client/api/StoreApi.java @@ -1,17 +1,18 @@ package io.swagger.client.api; +import com.sun.jersey.api.client.GenericType; + import io.swagger.client.ApiException; import io.swagger.client.ApiClient; import io.swagger.client.Configuration; import io.swagger.client.Pair; -import io.swagger.client.TypeRef; import java.util.Map; import io.swagger.client.model.Order; import java.util.*; -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-11-29T00:18:25.953+08:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-09T22:51:50.471-05:00") public class StoreApi { private ApiClient apiClient; @@ -37,9 +38,8 @@ public class StoreApi { * Returns a map of status codes to quantities * @return Map */ - public Map getInventory () throws ApiException { + public Map getInventory() throws ApiException { Object postBody = null; - byte[] postBinaryBody = null; // create path and map variables String path = "/store/inventory".replaceAll("\\{format\\}","json"); @@ -68,15 +68,9 @@ public class StoreApi { String[] authNames = new String[] { "api_key" }; - + GenericType> returnType = new GenericType>() {}; + return apiClient.invokeAPI(path, "GET", queryParams, postBody, headerParams, formParams, accept, contentType, authNames, returnType); - - TypeRef returnType = new TypeRef>() {}; - return apiClient.invokeAPI(path, "GET", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, returnType); - - - - } /** @@ -85,9 +79,8 @@ public class StoreApi { * @param body order placed for purchasing the pet * @return Order */ - public Order placeOrder (Order body) throws ApiException { + public Order placeOrder(Order body) throws ApiException { Object postBody = body; - byte[] postBinaryBody = null; // create path and map variables String path = "/store/order".replaceAll("\\{format\\}","json"); @@ -116,15 +109,9 @@ public class StoreApi { String[] authNames = new String[] { }; - + GenericType returnType = new GenericType() {}; + return apiClient.invokeAPI(path, "POST", queryParams, postBody, headerParams, formParams, accept, contentType, authNames, returnType); - - TypeRef returnType = new TypeRef() {}; - return apiClient.invokeAPI(path, "POST", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, returnType); - - - - } /** @@ -133,9 +120,8 @@ public class StoreApi { * @param orderId ID of pet that needs to be fetched * @return Order */ - public Order getOrderById (String orderId) throws ApiException { + public Order getOrderById(String orderId) throws ApiException { Object postBody = null; - byte[] postBinaryBody = null; // verify the required parameter 'orderId' is set if (orderId == null) { @@ -170,15 +156,9 @@ public class StoreApi { String[] authNames = new String[] { }; - + GenericType returnType = new GenericType() {}; + return apiClient.invokeAPI(path, "GET", queryParams, postBody, headerParams, formParams, accept, contentType, authNames, returnType); - - TypeRef returnType = new TypeRef() {}; - return apiClient.invokeAPI(path, "GET", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, returnType); - - - - } /** @@ -187,9 +167,8 @@ public class StoreApi { * @param orderId ID of the order that needs to be deleted * @return void */ - public void deleteOrder (String orderId) throws ApiException { + public void deleteOrder(String orderId) throws ApiException { Object postBody = null; - byte[] postBinaryBody = null; // verify the required parameter 'orderId' is set if (orderId == null) { @@ -224,14 +203,8 @@ public class StoreApi { String[] authNames = new String[] { }; - + apiClient.invokeAPI(path, "DELETE", queryParams, postBody, headerParams, formParams, accept, contentType, authNames, null); - - apiClient.invokeAPI(path, "DELETE", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, null); - - - - } } diff --git a/samples/client/petstore/java/default/src/main/java/io/swagger/client/api/UserApi.java b/samples/client/petstore/java/default/src/main/java/io/swagger/client/api/UserApi.java index 9a4f4086d34b..41b273b20b86 100644 --- a/samples/client/petstore/java/default/src/main/java/io/swagger/client/api/UserApi.java +++ b/samples/client/petstore/java/default/src/main/java/io/swagger/client/api/UserApi.java @@ -1,17 +1,18 @@ package io.swagger.client.api; +import com.sun.jersey.api.client.GenericType; + import io.swagger.client.ApiException; import io.swagger.client.ApiClient; import io.swagger.client.Configuration; import io.swagger.client.Pair; -import io.swagger.client.TypeRef; import io.swagger.client.model.User; import java.util.*; import java.util.*; -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-11-29T00:18:25.953+08:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-09T22:51:50.471-05:00") public class UserApi { private ApiClient apiClient; @@ -38,9 +39,8 @@ public class UserApi { * @param body Created user object * @return void */ - public void createUser (User body) throws ApiException { + public void createUser(User body) throws ApiException { Object postBody = body; - byte[] postBinaryBody = null; // create path and map variables String path = "/user".replaceAll("\\{format\\}","json"); @@ -69,14 +69,8 @@ public class UserApi { String[] authNames = new String[] { }; - + apiClient.invokeAPI(path, "POST", queryParams, postBody, headerParams, formParams, accept, contentType, authNames, null); - - apiClient.invokeAPI(path, "POST", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, null); - - - - } /** @@ -85,9 +79,8 @@ public class UserApi { * @param body List of user object * @return void */ - public void createUsersWithArrayInput (List body) throws ApiException { + public void createUsersWithArrayInput(List body) throws ApiException { Object postBody = body; - byte[] postBinaryBody = null; // create path and map variables String path = "/user/createWithArray".replaceAll("\\{format\\}","json"); @@ -116,14 +109,8 @@ public class UserApi { String[] authNames = new String[] { }; - + apiClient.invokeAPI(path, "POST", queryParams, postBody, headerParams, formParams, accept, contentType, authNames, null); - - apiClient.invokeAPI(path, "POST", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, null); - - - - } /** @@ -132,9 +119,8 @@ public class UserApi { * @param body List of user object * @return void */ - public void createUsersWithListInput (List body) throws ApiException { + public void createUsersWithListInput(List body) throws ApiException { Object postBody = body; - byte[] postBinaryBody = null; // create path and map variables String path = "/user/createWithList".replaceAll("\\{format\\}","json"); @@ -163,14 +149,8 @@ public class UserApi { String[] authNames = new String[] { }; - + apiClient.invokeAPI(path, "POST", queryParams, postBody, headerParams, formParams, accept, contentType, authNames, null); - - apiClient.invokeAPI(path, "POST", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, null); - - - - } /** @@ -180,9 +160,8 @@ public class UserApi { * @param password The password for login in clear text * @return String */ - public String loginUser (String username, String password) throws ApiException { + public String loginUser(String username, String password) throws ApiException { Object postBody = null; - byte[] postBinaryBody = null; // create path and map variables String path = "/user/login".replaceAll("\\{format\\}","json"); @@ -215,15 +194,9 @@ public class UserApi { String[] authNames = new String[] { }; - + GenericType returnType = new GenericType() {}; + return apiClient.invokeAPI(path, "GET", queryParams, postBody, headerParams, formParams, accept, contentType, authNames, returnType); - - TypeRef returnType = new TypeRef() {}; - return apiClient.invokeAPI(path, "GET", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, returnType); - - - - } /** @@ -231,9 +204,8 @@ public class UserApi { * * @return void */ - public void logoutUser () throws ApiException { + public void logoutUser() throws ApiException { Object postBody = null; - byte[] postBinaryBody = null; // create path and map variables String path = "/user/logout".replaceAll("\\{format\\}","json"); @@ -262,14 +234,8 @@ public class UserApi { String[] authNames = new String[] { }; - + apiClient.invokeAPI(path, "GET", queryParams, postBody, headerParams, formParams, accept, contentType, authNames, null); - - apiClient.invokeAPI(path, "GET", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, null); - - - - } /** @@ -278,9 +244,8 @@ public class UserApi { * @param username The name that needs to be fetched. Use user1 for testing. * @return User */ - public User getUserByName (String username) throws ApiException { + public User getUserByName(String username) throws ApiException { Object postBody = null; - byte[] postBinaryBody = null; // verify the required parameter 'username' is set if (username == null) { @@ -315,15 +280,9 @@ public class UserApi { String[] authNames = new String[] { }; - + GenericType returnType = new GenericType() {}; + return apiClient.invokeAPI(path, "GET", queryParams, postBody, headerParams, formParams, accept, contentType, authNames, returnType); - - TypeRef returnType = new TypeRef() {}; - return apiClient.invokeAPI(path, "GET", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, returnType); - - - - } /** @@ -333,9 +292,8 @@ public class UserApi { * @param body Updated user object * @return void */ - public void updateUser (String username, User body) throws ApiException { + public void updateUser(String username, User body) throws ApiException { Object postBody = body; - byte[] postBinaryBody = null; // verify the required parameter 'username' is set if (username == null) { @@ -370,14 +328,8 @@ public class UserApi { String[] authNames = new String[] { }; - + apiClient.invokeAPI(path, "PUT", queryParams, postBody, headerParams, formParams, accept, contentType, authNames, null); - - apiClient.invokeAPI(path, "PUT", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, null); - - - - } /** @@ -386,9 +338,8 @@ public class UserApi { * @param username The name that needs to be deleted * @return void */ - public void deleteUser (String username) throws ApiException { + public void deleteUser(String username) throws ApiException { Object postBody = null; - byte[] postBinaryBody = null; // verify the required parameter 'username' is set if (username == null) { @@ -423,14 +374,8 @@ public class UserApi { String[] authNames = new String[] { }; - + apiClient.invokeAPI(path, "DELETE", queryParams, postBody, headerParams, formParams, accept, contentType, authNames, null); - - apiClient.invokeAPI(path, "DELETE", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, null); - - - - } } diff --git a/samples/client/petstore/java/default/src/test/java/io/swagger/client/JSONTest.java b/samples/client/petstore/java/default/src/test/java/io/swagger/client/JSONTest.java deleted file mode 100644 index 1250a135078f..000000000000 --- a/samples/client/petstore/java/default/src/test/java/io/swagger/client/JSONTest.java +++ /dev/null @@ -1,52 +0,0 @@ -package io.swagger.client; - -import io.swagger.client.model.Order; - -import java.lang.Exception; -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.*; -import java.util.TimeZone; - -import org.junit.*; -import static org.junit.Assert.*; - - -public class JSONTest { - JSON json = null; - Order order = null; - - @Before - public void setup() { - json = new JSON(); - order = new Order(); - } - - @Test - public void testDefaultDate() throws Exception { - final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); - dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - final String dateStr = "2015-11-07T14:11:05.267Z"; - order.setShipDate(dateFormat.parse(dateStr)); - - String str = json.serialize(order); - TypeRef typeRef = new TypeRef() { }; - Order o = json.deserialize(str, typeRef); - assertEquals(dateStr, dateFormat.format(o.getShipDate())); - } - - @Test - public void testCustomDate() throws Exception { - final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX"); - dateFormat.setTimeZone(TimeZone.getTimeZone("GMT-2")); - final String dateStr = "2015-11-07T14:11:05-02:00"; - order.setShipDate(dateFormat.parse(dateStr)); - - json.setDateFormat(dateFormat); - String str = json.serialize(order); - TypeRef typeRef = new TypeRef() { }; - Order o = json.deserialize(str, typeRef); - assertEquals(dateStr, dateFormat.format(o.getShipDate())); - } -} \ No newline at end of file From 0f67be55907323d80d1c2600ba5e7fc31f27a2a1 Mon Sep 17 00:00:00 2001 From: evigeant Date: Tue, 8 Dec 2015 22:23:27 -0500 Subject: [PATCH 41/71] Simplified Jersey2 java client by letting Jersey do most serialization and deserialization --- .../Java/libraries/jersey2/ApiClient.mustache | 97 +++++++------------ .../Java/libraries/jersey2/JSON.mustache | 36 +++++++ .../Java/libraries/jersey2/api.mustache | 5 +- .../Java/libraries/jersey2/pom.mustache | 7 +- 4 files changed, 79 insertions(+), 66 deletions(-) create mode 100644 modules/swagger-codegen/src/main/resources/Java/libraries/jersey2/JSON.mustache diff --git a/modules/swagger-codegen/src/main/resources/Java/libraries/jersey2/ApiClient.mustache b/modules/swagger-codegen/src/main/resources/Java/libraries/jersey2/ApiClient.mustache index 4f08158ab759..f482b8c34d4d 100644 --- a/modules/swagger-codegen/src/main/resources/Java/libraries/jersey2/ApiClient.mustache +++ b/modules/swagger-codegen/src/main/resources/Java/libraries/jersey2/ApiClient.mustache @@ -6,6 +6,7 @@ import javax.ws.rs.client.Entity; import javax.ws.rs.client.Invocation; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.Form; +import javax.ws.rs.core.GenericType; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; @@ -29,13 +30,11 @@ import java.util.TimeZone; import java.net.URLEncoder; -import java.io.IOException; import java.io.File; import java.io.UnsupportedEncodingException; import java.text.DateFormat; import java.text.SimpleDateFormat; -import java.text.ParseException; import {{invokerPackage}}.auth.Authentication; import {{invokerPackage}}.auth.HttpBasicAuth; @@ -412,18 +411,39 @@ public class ApiClient { * Serialize the given Java object into string entity according the given * Content-Type (only JSON is supported for now). */ - public Entity serialize(Object obj, String contentType) throws ApiException { - if (isJsonMime(contentType)) { - return Entity.json(json.serialize(obj)); + public Entity serialize(Object obj, Map formParams, String contentType) throws ApiException { + Entity entity = null; + if (contentType.startsWith("multipart/form-data")) { + MultiPart multiPart = new MultiPart(); + for (Entry param: formParams.entrySet()) { + if (param.getValue() instanceof File) { + File file = (File) param.getValue(); + FormDataContentDisposition contentDisp = FormDataContentDisposition.name(param.getKey()) + .fileName(file.getName()).size(file.length()).build(); + multiPart.bodyPart(new FormDataBodyPart(contentDisp, file, MediaType.APPLICATION_OCTET_STREAM_TYPE)); + } else { + FormDataContentDisposition contentDisp = FormDataContentDisposition.name(param.getKey()).build(); + multiPart.bodyPart(new FormDataBodyPart(contentDisp, parameterToString(param.getValue()))); + } + } + entity = Entity.entity(multiPart, MediaType.MULTIPART_FORM_DATA_TYPE); + } else if (contentType.startsWith("application/x-www-form-urlencoded")) { + Form form = new Form(); + for (Entry param: formParams.entrySet()) { + form.param(param.getKey(), parameterToString(param.getValue())); + } + entity = Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE); } else { - throw new ApiException(400, "can not serialize object into Content-Type: " + contentType); + // We let jersey handle the serialization + entity = Entity.entity(obj, contentType); } + return entity; } /** * Deserialize response body to Java object according to the Content-Type. */ - public T deserialize(Response response, TypeRef returnType) throws ApiException { + public T deserialize(Response response, GenericType returnType) throws ApiException { String contentType = null; List contentTypes = response.getHeaders().get("Content-Type"); if (contentTypes != null && !contentTypes.isEmpty()) @@ -431,24 +451,7 @@ public class ApiClient { if (contentType == null) throw new ApiException(500, "missing Content-Type in response"); - String body; - if (response.hasEntity()) - body = (String) response.readEntity(String.class); - else - body = ""; - - if (isJsonMime(contentType)) { - return json.deserialize(body, returnType); - } else if (returnType.getType().equals(String.class)) { - // Expecting string, return the raw response body. - return (T) body; - } else { - throw new ApiException( - 500, - "Content type \"" + contentType + "\" is not supported for type: " - + returnType.getType() - ); - } + return response.readEntity(returnType); } /** @@ -466,7 +469,7 @@ public class ApiClient { * @param returnType The return type into which to deserialize the response * @return The response body in type of string */ - public T invokeAPI(String path, String method, List queryParams, Object body, Map headerParams, Map formParams, String accept, String contentType, String[] authNames, TypeRef returnType) throws ApiException { + public T invokeAPI(String path, String method, List queryParams, Object body, Map headerParams, Map formParams, String accept, String contentType, String[] authNames, GenericType returnType) throws ApiException { updateParamsForAuth(authNames, queryParams, headerParams); WebTarget target = client.target(this.basePath).path(path); @@ -497,50 +500,16 @@ public class ApiClient { } } - Entity formEntity = null; - - if (contentType.startsWith("multipart/form-data")) { - MultiPart multiPart = new MultiPart(); - for (Entry param: formParams.entrySet()) { - if (param.getValue() instanceof File) { - File file = (File) param.getValue(); - FormDataContentDisposition contentDisp = FormDataContentDisposition.name(param.getKey()) - .fileName(file.getName()).size(file.length()).build(); - multiPart.bodyPart(new FormDataBodyPart(contentDisp, file, MediaType.APPLICATION_OCTET_STREAM_TYPE)); - } else { - FormDataContentDisposition contentDisp = FormDataContentDisposition.name(param.getKey()).build(); - multiPart.bodyPart(new FormDataBodyPart(contentDisp, parameterToString(param.getValue()))); - } - } - formEntity = Entity.entity(multiPart, MediaType.MULTIPART_FORM_DATA_TYPE); - } else if (contentType.startsWith("application/x-www-form-urlencoded")) { - Form form = new Form(); - for (Entry param: formParams.entrySet()) { - form.param(param.getKey(), parameterToString(param.getValue())); - } - formEntity = Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE); - } + Entity entity = serialize(body, formParams, contentType); Response response = null; if ("GET".equals(method)) { response = invocationBuilder.get(); } else if ("POST".equals(method)) { - if (formEntity != null) { - response = invocationBuilder.post(formEntity); - } else if (body == null) { - response = invocationBuilder.post(null); - } else { - response = invocationBuilder.post(serialize(body, contentType)); - } + response = invocationBuilder.post(entity); } else if ("PUT".equals(method)) { - if (formEntity != null) { - response = invocationBuilder.put(formEntity); - } else if (body == null) { - response = invocationBuilder.put(null); - } else { - response = invocationBuilder.put(serialize(body, contentType)); - } + response = invocationBuilder.put(entity); } else if ("DELETE".equals(method)) { response = invocationBuilder.delete(); } else { @@ -579,6 +548,8 @@ public class ApiClient { private void buildClient() { final ClientConfig clientConfig = new ClientConfig(); clientConfig.register(MultiPartFeature.class); + clientConfig.register(json); + clientConfig.register(org.glassfish.jersey.jackson.JacksonFeature.class); if (debugging) { clientConfig.register(LoggingFilter.class); } diff --git a/modules/swagger-codegen/src/main/resources/Java/libraries/jersey2/JSON.mustache b/modules/swagger-codegen/src/main/resources/Java/libraries/jersey2/JSON.mustache new file mode 100644 index 000000000000..cc3f1baba140 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Java/libraries/jersey2/JSON.mustache @@ -0,0 +1,36 @@ +package {{invokerPackage}}; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.datatype.joda.*; + +import java.text.DateFormat; + +import javax.ws.rs.ext.ContextResolver; + +{{>generatedAnnotation}} +public class JSON implements ContextResolver { + private ObjectMapper mapper; + + public JSON() { + mapper = new ObjectMapper(); + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING); + mapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING); + mapper.registerModule(new JodaModule()); + } + + /** + * Set the date format for JSON (de)serialization with Date properties. + */ + public void setDateFormat(DateFormat dateFormat) { + mapper.setDateFormat(dateFormat); + } + + @Override + public ObjectMapper getContext(Class type) { + return mapper; + } +} diff --git a/modules/swagger-codegen/src/main/resources/Java/libraries/jersey2/api.mustache b/modules/swagger-codegen/src/main/resources/Java/libraries/jersey2/api.mustache index 0d5c3bcf7f0b..f9572359ded9 100644 --- a/modules/swagger-codegen/src/main/resources/Java/libraries/jersey2/api.mustache +++ b/modules/swagger-codegen/src/main/resources/Java/libraries/jersey2/api.mustache @@ -4,7 +4,8 @@ import {{invokerPackage}}.ApiException; import {{invokerPackage}}.ApiClient; import {{invokerPackage}}.Configuration; import {{invokerPackage}}.Pair; -import {{invokerPackage}}.TypeRef; + +import javax.ws.rs.core.GenericType; {{#imports}}import {{import}}; {{/imports}} @@ -83,7 +84,7 @@ public class {{classname}} { String[] {{localVariablePrefix}}authNames = new String[] { {{#authMethods}}"{{name}}"{{#hasMore}}, {{/hasMore}}{{/authMethods}} }; {{#returnType}} - TypeRef {{localVariablePrefix}}returnType = new TypeRef<{{{returnType}}}>() {}; + GenericType<{{{returnType}}}> {{localVariablePrefix}}returnType = new GenericType<{{{returnType}}}>() {}; return {{localVariablePrefix}}apiClient.invokeAPI({{localVariablePrefix}}path, "{{httpMethod}}", {{localVariablePrefix}}queryParams, {{localVariablePrefix}}postBody, {{localVariablePrefix}}headerParams, {{localVariablePrefix}}formParams, {{localVariablePrefix}}accept, {{localVariablePrefix}}contentType, {{localVariablePrefix}}authNames, {{localVariablePrefix}}returnType); {{/returnType}}{{^returnType}} {{localVariablePrefix}}apiClient.invokeAPI({{localVariablePrefix}}path, "{{httpMethod}}", {{localVariablePrefix}}queryParams, {{localVariablePrefix}}postBody, {{localVariablePrefix}}headerParams, {{localVariablePrefix}}formParams, {{localVariablePrefix}}accept, {{localVariablePrefix}}contentType, {{localVariablePrefix}}authNames, null); diff --git a/modules/swagger-codegen/src/main/resources/Java/libraries/jersey2/pom.mustache b/modules/swagger-codegen/src/main/resources/Java/libraries/jersey2/pom.mustache index dbe0138aa54b..76f2164a1add 100644 --- a/modules/swagger-codegen/src/main/resources/Java/libraries/jersey2/pom.mustache +++ b/modules/swagger-codegen/src/main/resources/Java/libraries/jersey2/pom.mustache @@ -124,7 +124,12 @@ jersey-media-multipart ${jersey-version} - + + org.glassfish.jersey.media + jersey-media-json-jackson + 2.22.1 + + com.fasterxml.jackson.core From a3024a3553f773da1fe4ebf725ce37046c43313f Mon Sep 17 00:00:00 2001 From: evigeant Date: Wed, 9 Dec 2015 12:37:12 -0500 Subject: [PATCH 42/71] Updated PetStore sample for java client jersey2 --- samples/client/petstore/java/jersey2/pom.xml | 7 +- .../java/io/swagger/client/ApiClient.java | 99 +++++++------------ .../src/main/java/io/swagger/client/JSON.java | 40 ++------ .../main/java/io/swagger/client/TypeRef.java | 26 ----- .../java/io/swagger/client/api/PetApi.java | 27 ++--- .../java/io/swagger/client/api/StoreApi.java | 19 ++-- .../java/io/swagger/client/api/UserApi.java | 25 ++--- .../test/java/io/swagger/client/JSONTest.java | 12 +-- 8 files changed, 88 insertions(+), 167 deletions(-) delete mode 100644 samples/client/petstore/java/jersey2/src/main/java/io/swagger/client/TypeRef.java diff --git a/samples/client/petstore/java/jersey2/pom.xml b/samples/client/petstore/java/jersey2/pom.xml index 0881cc293746..6b0ba2cba08f 100644 --- a/samples/client/petstore/java/jersey2/pom.xml +++ b/samples/client/petstore/java/jersey2/pom.xml @@ -124,7 +124,12 @@ jersey-media-multipart ${jersey-version} - + + org.glassfish.jersey.media + jersey-media-json-jackson + 2.22.1 + + com.fasterxml.jackson.core diff --git a/samples/client/petstore/java/jersey2/src/main/java/io/swagger/client/ApiClient.java b/samples/client/petstore/java/jersey2/src/main/java/io/swagger/client/ApiClient.java index c5c74cc11e4e..4ca24fbabb0c 100644 --- a/samples/client/petstore/java/jersey2/src/main/java/io/swagger/client/ApiClient.java +++ b/samples/client/petstore/java/jersey2/src/main/java/io/swagger/client/ApiClient.java @@ -6,6 +6,7 @@ import javax.ws.rs.client.Entity; import javax.ws.rs.client.Invocation; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.Form; +import javax.ws.rs.core.GenericType; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; @@ -29,20 +30,18 @@ import java.util.TimeZone; import java.net.URLEncoder; -import java.io.IOException; import java.io.File; import java.io.UnsupportedEncodingException; import java.text.DateFormat; import java.text.SimpleDateFormat; -import java.text.ParseException; import io.swagger.client.auth.Authentication; import io.swagger.client.auth.HttpBasicAuth; import io.swagger.client.auth.ApiKeyAuth; import io.swagger.client.auth.OAuth; -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-09T16:27:55.818+08:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-09T12:31:44.572-05:00") public class ApiClient { private Client client; private Map hostMap = new HashMap(); @@ -411,18 +410,39 @@ public class ApiClient { * Serialize the given Java object into string entity according the given * Content-Type (only JSON is supported for now). */ - public Entity serialize(Object obj, String contentType) throws ApiException { - if (isJsonMime(contentType)) { - return Entity.json(json.serialize(obj)); + public Entity serialize(Object obj, Map formParams, String contentType) throws ApiException { + Entity entity = null; + if (contentType.startsWith("multipart/form-data")) { + MultiPart multiPart = new MultiPart(); + for (Entry param: formParams.entrySet()) { + if (param.getValue() instanceof File) { + File file = (File) param.getValue(); + FormDataContentDisposition contentDisp = FormDataContentDisposition.name(param.getKey()) + .fileName(file.getName()).size(file.length()).build(); + multiPart.bodyPart(new FormDataBodyPart(contentDisp, file, MediaType.APPLICATION_OCTET_STREAM_TYPE)); + } else { + FormDataContentDisposition contentDisp = FormDataContentDisposition.name(param.getKey()).build(); + multiPart.bodyPart(new FormDataBodyPart(contentDisp, parameterToString(param.getValue()))); + } + } + entity = Entity.entity(multiPart, MediaType.MULTIPART_FORM_DATA_TYPE); + } else if (contentType.startsWith("application/x-www-form-urlencoded")) { + Form form = new Form(); + for (Entry param: formParams.entrySet()) { + form.param(param.getKey(), parameterToString(param.getValue())); + } + entity = Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE); } else { - throw new ApiException(400, "can not serialize object into Content-Type: " + contentType); + // We let jersey handle the serialization + entity = Entity.entity(obj, contentType); } + return entity; } /** * Deserialize response body to Java object according to the Content-Type. */ - public T deserialize(Response response, TypeRef returnType) throws ApiException { + public T deserialize(Response response, GenericType returnType) throws ApiException { String contentType = null; List contentTypes = response.getHeaders().get("Content-Type"); if (contentTypes != null && !contentTypes.isEmpty()) @@ -430,24 +450,7 @@ public class ApiClient { if (contentType == null) throw new ApiException(500, "missing Content-Type in response"); - String body; - if (response.hasEntity()) - body = (String) response.readEntity(String.class); - else - body = ""; - - if (isJsonMime(contentType)) { - return json.deserialize(body, returnType); - } else if (returnType.getType().equals(String.class)) { - // Expecting string, return the raw response body. - return (T) body; - } else { - throw new ApiException( - 500, - "Content type \"" + contentType + "\" is not supported for type: " - + returnType.getType() - ); - } + return response.readEntity(returnType); } /** @@ -465,7 +468,7 @@ public class ApiClient { * @param returnType The return type into which to deserialize the response * @return The response body in type of string */ - public T invokeAPI(String path, String method, List queryParams, Object body, Map headerParams, Map formParams, String accept, String contentType, String[] authNames, TypeRef returnType) throws ApiException { + public T invokeAPI(String path, String method, List queryParams, Object body, Map headerParams, Map formParams, String accept, String contentType, String[] authNames, GenericType returnType) throws ApiException { updateParamsForAuth(authNames, queryParams, headerParams); WebTarget target = client.target(this.basePath).path(path); @@ -496,50 +499,16 @@ public class ApiClient { } } - Entity formEntity = null; - - if (contentType.startsWith("multipart/form-data")) { - MultiPart multiPart = new MultiPart(); - for (Entry param: formParams.entrySet()) { - if (param.getValue() instanceof File) { - File file = (File) param.getValue(); - FormDataContentDisposition contentDisp = FormDataContentDisposition.name(param.getKey()) - .fileName(file.getName()).size(file.length()).build(); - multiPart.bodyPart(new FormDataBodyPart(contentDisp, file, MediaType.APPLICATION_OCTET_STREAM_TYPE)); - } else { - FormDataContentDisposition contentDisp = FormDataContentDisposition.name(param.getKey()).build(); - multiPart.bodyPart(new FormDataBodyPart(contentDisp, parameterToString(param.getValue()))); - } - } - formEntity = Entity.entity(multiPart, MediaType.MULTIPART_FORM_DATA_TYPE); - } else if (contentType.startsWith("application/x-www-form-urlencoded")) { - Form form = new Form(); - for (Entry param: formParams.entrySet()) { - form.param(param.getKey(), parameterToString(param.getValue())); - } - formEntity = Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE); - } + Entity entity = serialize(body, formParams, contentType); Response response = null; if ("GET".equals(method)) { response = invocationBuilder.get(); } else if ("POST".equals(method)) { - if (formEntity != null) { - response = invocationBuilder.post(formEntity); - } else if (body == null) { - response = invocationBuilder.post(null); - } else { - response = invocationBuilder.post(serialize(body, contentType)); - } + response = invocationBuilder.post(entity); } else if ("PUT".equals(method)) { - if (formEntity != null) { - response = invocationBuilder.put(formEntity); - } else if (body == null) { - response = invocationBuilder.put(null); - } else { - response = invocationBuilder.put(serialize(body, contentType)); - } + response = invocationBuilder.put(entity); } else if ("DELETE".equals(method)) { response = invocationBuilder.delete(); } else { @@ -578,6 +547,8 @@ public class ApiClient { private void buildClient() { final ClientConfig clientConfig = new ClientConfig(); clientConfig.register(MultiPartFeature.class); + clientConfig.register(json); + clientConfig.register(org.glassfish.jersey.jackson.JacksonFeature.class); if (debugging) { clientConfig.register(LoggingFilter.class); } diff --git a/samples/client/petstore/java/jersey2/src/main/java/io/swagger/client/JSON.java b/samples/client/petstore/java/jersey2/src/main/java/io/swagger/client/JSON.java index 9116d3663083..aab2d27e4638 100644 --- a/samples/client/petstore/java/jersey2/src/main/java/io/swagger/client/JSON.java +++ b/samples/client/petstore/java/jersey2/src/main/java/io/swagger/client/JSON.java @@ -6,10 +6,10 @@ import com.fasterxml.jackson.datatype.joda.*; import java.text.DateFormat; -import java.io.IOException; +import javax.ws.rs.ext.ContextResolver; -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-11-29T00:18:01.946+08:00") -public class JSON { +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-09T12:31:44.572-05:00") +public class JSON implements ContextResolver { private ObjectMapper mapper; public JSON() { @@ -29,36 +29,8 @@ public class JSON { mapper.setDateFormat(dateFormat); } - /** - * Serialize the given Java object into JSON string. - */ - public String serialize(Object obj) throws ApiException { - try { - if (obj != null) - return mapper.writeValueAsString(obj); - else - return null; - } catch (Exception e) { - throw new ApiException(400, e.getMessage()); - } - } - - /** - * Deserialize the given JSON string to Java object. - * - * @param body The JSON string - * @param returnType The type to deserialize inot - * @return The deserialized Java object - */ - public T deserialize(String body, TypeRef returnType) throws ApiException { - JavaType javaType = mapper.constructType(returnType.getType()); - try { - return mapper.readValue(body, javaType); - } catch (IOException e) { - if (returnType.getType().equals(String.class)) - return (T) body; - else - throw new ApiException(500, e.getMessage(), null, body); - } + @Override + public ObjectMapper getContext(Class type) { + return mapper; } } diff --git a/samples/client/petstore/java/jersey2/src/main/java/io/swagger/client/TypeRef.java b/samples/client/petstore/java/jersey2/src/main/java/io/swagger/client/TypeRef.java deleted file mode 100644 index 9c97f34cd792..000000000000 --- a/samples/client/petstore/java/jersey2/src/main/java/io/swagger/client/TypeRef.java +++ /dev/null @@ -1,26 +0,0 @@ -package io.swagger.client; - -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; - -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-11-29T00:18:01.946+08:00") -public class TypeRef { - private final Type type; - - public TypeRef() { - this.type = getGenericType(getClass()); - } - - private static Type getGenericType(Class klass) { - Type superclass = klass.getGenericSuperclass(); - if (superclass instanceof Class) { - throw new RuntimeException("No type parameter provided"); - } - ParameterizedType parameterized = (ParameterizedType) superclass; - return parameterized.getActualTypeArguments()[0]; - } - - public Type getType() { - return type; - } -} diff --git a/samples/client/petstore/java/jersey2/src/main/java/io/swagger/client/api/PetApi.java b/samples/client/petstore/java/jersey2/src/main/java/io/swagger/client/api/PetApi.java index a645de12c719..ab33fca7c798 100644 --- a/samples/client/petstore/java/jersey2/src/main/java/io/swagger/client/api/PetApi.java +++ b/samples/client/petstore/java/jersey2/src/main/java/io/swagger/client/api/PetApi.java @@ -4,14 +4,15 @@ import io.swagger.client.ApiException; import io.swagger.client.ApiClient; import io.swagger.client.Configuration; import io.swagger.client.Pair; -import io.swagger.client.TypeRef; + +import javax.ws.rs.core.GenericType; import io.swagger.client.model.Pet; import java.io.File; import java.util.*; -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-11-29T00:18:01.946+08:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-09T12:31:44.572-05:00") public class PetApi { private ApiClient apiClient; @@ -38,7 +39,7 @@ public class PetApi { * @param body Pet object that needs to be added to the store * @return void */ - public void updatePet (Pet body) throws ApiException { + public void updatePet(Pet body) throws ApiException { Object postBody = body; // create path and map variables @@ -78,7 +79,7 @@ public class PetApi { * @param body Pet object that needs to be added to the store * @return void */ - public void addPet (Pet body) throws ApiException { + public void addPet(Pet body) throws ApiException { Object postBody = body; // create path and map variables @@ -118,7 +119,7 @@ public class PetApi { * @param status Status values that need to be considered for filter * @return List */ - public List findPetsByStatus (List status) throws ApiException { + public List findPetsByStatus(List status) throws ApiException { Object postBody = null; // create path and map variables @@ -150,7 +151,7 @@ public class PetApi { String[] authNames = new String[] { "petstore_auth" }; - TypeRef returnType = new TypeRef>() {}; + GenericType> returnType = new GenericType>() {}; return apiClient.invokeAPI(path, "GET", queryParams, postBody, headerParams, formParams, accept, contentType, authNames, returnType); } @@ -161,7 +162,7 @@ public class PetApi { * @param tags Tags to filter by * @return List */ - public List findPetsByTags (List tags) throws ApiException { + public List findPetsByTags(List tags) throws ApiException { Object postBody = null; // create path and map variables @@ -193,7 +194,7 @@ public class PetApi { String[] authNames = new String[] { "petstore_auth" }; - TypeRef returnType = new TypeRef>() {}; + GenericType> returnType = new GenericType>() {}; return apiClient.invokeAPI(path, "GET", queryParams, postBody, headerParams, formParams, accept, contentType, authNames, returnType); } @@ -204,7 +205,7 @@ public class PetApi { * @param petId ID of pet that needs to be fetched * @return Pet */ - public Pet getPetById (Long petId) throws ApiException { + public Pet getPetById(Long petId) throws ApiException { Object postBody = null; // verify the required parameter 'petId' is set @@ -240,7 +241,7 @@ public class PetApi { String[] authNames = new String[] { "api_key" }; - TypeRef returnType = new TypeRef() {}; + GenericType returnType = new GenericType() {}; return apiClient.invokeAPI(path, "GET", queryParams, postBody, headerParams, formParams, accept, contentType, authNames, returnType); } @@ -253,7 +254,7 @@ public class PetApi { * @param status Updated status of the pet * @return void */ - public void updatePetWithForm (String petId, String name, String status) throws ApiException { + public void updatePetWithForm(String petId, String name, String status) throws ApiException { Object postBody = null; // verify the required parameter 'petId' is set @@ -304,7 +305,7 @@ public class PetApi { * @param apiKey * @return void */ - public void deletePet (Long petId, String apiKey) throws ApiException { + public void deletePet(Long petId, String apiKey) throws ApiException { Object postBody = null; // verify the required parameter 'petId' is set @@ -354,7 +355,7 @@ public class PetApi { * @param file file to upload * @return void */ - public void uploadFile (Long petId, String additionalMetadata, File file) throws ApiException { + public void uploadFile(Long petId, String additionalMetadata, File file) throws ApiException { Object postBody = null; // verify the required parameter 'petId' is set diff --git a/samples/client/petstore/java/jersey2/src/main/java/io/swagger/client/api/StoreApi.java b/samples/client/petstore/java/jersey2/src/main/java/io/swagger/client/api/StoreApi.java index 7253d1909b60..5dfdbcc3e62c 100644 --- a/samples/client/petstore/java/jersey2/src/main/java/io/swagger/client/api/StoreApi.java +++ b/samples/client/petstore/java/jersey2/src/main/java/io/swagger/client/api/StoreApi.java @@ -4,14 +4,15 @@ import io.swagger.client.ApiException; import io.swagger.client.ApiClient; import io.swagger.client.Configuration; import io.swagger.client.Pair; -import io.swagger.client.TypeRef; + +import javax.ws.rs.core.GenericType; import java.util.Map; import io.swagger.client.model.Order; import java.util.*; -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-11-29T00:18:01.946+08:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-09T12:31:44.572-05:00") public class StoreApi { private ApiClient apiClient; @@ -37,7 +38,7 @@ public class StoreApi { * Returns a map of status codes to quantities * @return Map */ - public Map getInventory () throws ApiException { + public Map getInventory() throws ApiException { Object postBody = null; // create path and map variables @@ -67,7 +68,7 @@ public class StoreApi { String[] authNames = new String[] { "api_key" }; - TypeRef returnType = new TypeRef>() {}; + GenericType> returnType = new GenericType>() {}; return apiClient.invokeAPI(path, "GET", queryParams, postBody, headerParams, formParams, accept, contentType, authNames, returnType); } @@ -78,7 +79,7 @@ public class StoreApi { * @param body order placed for purchasing the pet * @return Order */ - public Order placeOrder (Order body) throws ApiException { + public Order placeOrder(Order body) throws ApiException { Object postBody = body; // create path and map variables @@ -108,7 +109,7 @@ public class StoreApi { String[] authNames = new String[] { }; - TypeRef returnType = new TypeRef() {}; + GenericType returnType = new GenericType() {}; return apiClient.invokeAPI(path, "POST", queryParams, postBody, headerParams, formParams, accept, contentType, authNames, returnType); } @@ -119,7 +120,7 @@ public class StoreApi { * @param orderId ID of pet that needs to be fetched * @return Order */ - public Order getOrderById (String orderId) throws ApiException { + public Order getOrderById(String orderId) throws ApiException { Object postBody = null; // verify the required parameter 'orderId' is set @@ -155,7 +156,7 @@ public class StoreApi { String[] authNames = new String[] { }; - TypeRef returnType = new TypeRef() {}; + GenericType returnType = new GenericType() {}; return apiClient.invokeAPI(path, "GET", queryParams, postBody, headerParams, formParams, accept, contentType, authNames, returnType); } @@ -166,7 +167,7 @@ public class StoreApi { * @param orderId ID of the order that needs to be deleted * @return void */ - public void deleteOrder (String orderId) throws ApiException { + public void deleteOrder(String orderId) throws ApiException { Object postBody = null; // verify the required parameter 'orderId' is set diff --git a/samples/client/petstore/java/jersey2/src/main/java/io/swagger/client/api/UserApi.java b/samples/client/petstore/java/jersey2/src/main/java/io/swagger/client/api/UserApi.java index d6115d939fc3..0424382e7c33 100644 --- a/samples/client/petstore/java/jersey2/src/main/java/io/swagger/client/api/UserApi.java +++ b/samples/client/petstore/java/jersey2/src/main/java/io/swagger/client/api/UserApi.java @@ -4,14 +4,15 @@ import io.swagger.client.ApiException; import io.swagger.client.ApiClient; import io.swagger.client.Configuration; import io.swagger.client.Pair; -import io.swagger.client.TypeRef; + +import javax.ws.rs.core.GenericType; import io.swagger.client.model.User; import java.util.*; import java.util.*; -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-11-29T00:18:01.946+08:00") +@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaClientCodegen", date = "2015-12-09T12:31:44.572-05:00") public class UserApi { private ApiClient apiClient; @@ -38,7 +39,7 @@ public class UserApi { * @param body Created user object * @return void */ - public void createUser (User body) throws ApiException { + public void createUser(User body) throws ApiException { Object postBody = body; // create path and map variables @@ -78,7 +79,7 @@ public class UserApi { * @param body List of user object * @return void */ - public void createUsersWithArrayInput (List body) throws ApiException { + public void createUsersWithArrayInput(List body) throws ApiException { Object postBody = body; // create path and map variables @@ -118,7 +119,7 @@ public class UserApi { * @param body List of user object * @return void */ - public void createUsersWithListInput (List body) throws ApiException { + public void createUsersWithListInput(List body) throws ApiException { Object postBody = body; // create path and map variables @@ -159,7 +160,7 @@ public class UserApi { * @param password The password for login in clear text * @return String */ - public String loginUser (String username, String password) throws ApiException { + public String loginUser(String username, String password) throws ApiException { Object postBody = null; // create path and map variables @@ -193,7 +194,7 @@ public class UserApi { String[] authNames = new String[] { }; - TypeRef returnType = new TypeRef() {}; + GenericType returnType = new GenericType() {}; return apiClient.invokeAPI(path, "GET", queryParams, postBody, headerParams, formParams, accept, contentType, authNames, returnType); } @@ -203,7 +204,7 @@ public class UserApi { * * @return void */ - public void logoutUser () throws ApiException { + public void logoutUser() throws ApiException { Object postBody = null; // create path and map variables @@ -243,7 +244,7 @@ public class UserApi { * @param username The name that needs to be fetched. Use user1 for testing. * @return User */ - public User getUserByName (String username) throws ApiException { + public User getUserByName(String username) throws ApiException { Object postBody = null; // verify the required parameter 'username' is set @@ -279,7 +280,7 @@ public class UserApi { String[] authNames = new String[] { }; - TypeRef returnType = new TypeRef() {}; + GenericType returnType = new GenericType() {}; return apiClient.invokeAPI(path, "GET", queryParams, postBody, headerParams, formParams, accept, contentType, authNames, returnType); } @@ -291,7 +292,7 @@ public class UserApi { * @param body Updated user object * @return void */ - public void updateUser (String username, User body) throws ApiException { + public void updateUser(String username, User body) throws ApiException { Object postBody = body; // verify the required parameter 'username' is set @@ -337,7 +338,7 @@ public class UserApi { * @param username The name that needs to be deleted * @return void */ - public void deleteUser (String username) throws ApiException { + public void deleteUser(String username) throws ApiException { Object postBody = null; // verify the required parameter 'username' is set diff --git a/samples/client/petstore/java/jersey2/src/test/java/io/swagger/client/JSONTest.java b/samples/client/petstore/java/jersey2/src/test/java/io/swagger/client/JSONTest.java index 1250a135078f..f10909ab9e73 100644 --- a/samples/client/petstore/java/jersey2/src/test/java/io/swagger/client/JSONTest.java +++ b/samples/client/petstore/java/jersey2/src/test/java/io/swagger/client/JSONTest.java @@ -4,9 +4,7 @@ import io.swagger.client.model.Order; import java.lang.Exception; import java.text.DateFormat; -import java.text.ParseException; import java.text.SimpleDateFormat; -import java.util.*; import java.util.TimeZone; import org.junit.*; @@ -30,9 +28,8 @@ public class JSONTest { final String dateStr = "2015-11-07T14:11:05.267Z"; order.setShipDate(dateFormat.parse(dateStr)); - String str = json.serialize(order); - TypeRef typeRef = new TypeRef() { }; - Order o = json.deserialize(str, typeRef); + String str = json.getContext(null).writeValueAsString(order); + Order o = json.getContext(null).readValue(str, Order.class); assertEquals(dateStr, dateFormat.format(o.getShipDate())); } @@ -44,9 +41,8 @@ public class JSONTest { order.setShipDate(dateFormat.parse(dateStr)); json.setDateFormat(dateFormat); - String str = json.serialize(order); - TypeRef typeRef = new TypeRef() { }; - Order o = json.deserialize(str, typeRef); + String str = json.getContext(null).writeValueAsString(order); + Order o = json.getContext(null).readValue(str, Order.class); assertEquals(dateStr, dateFormat.format(o.getShipDate())); } } \ No newline at end of file From cf3144d31fe3970c28a0b3debcb4fa30c3c0f651 Mon Sep 17 00:00:00 2001 From: Jeff Kwan Date: Thu, 10 Dec 2015 19:56:10 -0500 Subject: [PATCH 43/71] [C#] Fix date-time serialization to be ISO 8601 Fix the date-time serialization so that it's actually ISO 8601 compliant, currently it generates a date-time string Issue #1705 --- .../src/main/resources/CsharpDotNet2/ApiClient.mustache | 2 +- .../src/main/resources/csharp/ApiClient.mustache | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/swagger-codegen/src/main/resources/CsharpDotNet2/ApiClient.mustache b/modules/swagger-codegen/src/main/resources/CsharpDotNet2/ApiClient.mustache index 8e64db5af313..1d3fa50a284f 100644 --- a/modules/swagger-codegen/src/main/resources/CsharpDotNet2/ApiClient.mustache +++ b/modules/swagger-codegen/src/main/resources/CsharpDotNet2/ApiClient.mustache @@ -143,7 +143,7 @@ namespace {{packageName}}.Client public string ParameterToString(object obj) { if (obj is DateTime) - return ((DateTime)obj).ToString ("u"); + return ((DateTime)obj).ToString ("o"); else if (obj is List) return String.Join(",", (obj as List).ToArray()); else diff --git a/modules/swagger-codegen/src/main/resources/csharp/ApiClient.mustache b/modules/swagger-codegen/src/main/resources/csharp/ApiClient.mustache index 5dda78a41a46..cbbcf1e743f9 100644 --- a/modules/swagger-codegen/src/main/resources/csharp/ApiClient.mustache +++ b/modules/swagger-codegen/src/main/resources/csharp/ApiClient.mustache @@ -156,7 +156,7 @@ namespace {{packageName}}.Client public string ParameterToString(object obj) { if (obj is DateTime) - return ((DateTime)obj).ToString ("u"); + return ((DateTime)obj).ToString ("o"); else if (obj is IList) { string flattenString = ""; From 23fa84bff8cae86d73a1fbddd05470ff1ed3eab1 Mon Sep 17 00:00:00 2001 From: Jeff Kwan Date: Thu, 10 Dec 2015 20:03:29 -0500 Subject: [PATCH 44/71] Add some reasonable comments to this --- .../src/main/resources/CsharpDotNet2/ApiClient.mustache | 3 +++ .../src/main/resources/csharp/ApiClient.mustache | 3 +++ 2 files changed, 6 insertions(+) diff --git a/modules/swagger-codegen/src/main/resources/CsharpDotNet2/ApiClient.mustache b/modules/swagger-codegen/src/main/resources/CsharpDotNet2/ApiClient.mustache index 1d3fa50a284f..6d5e45c186e1 100644 --- a/modules/swagger-codegen/src/main/resources/CsharpDotNet2/ApiClient.mustache +++ b/modules/swagger-codegen/src/main/resources/CsharpDotNet2/ApiClient.mustache @@ -143,6 +143,9 @@ namespace {{packageName}}.Client public string ParameterToString(object obj) { if (obj is DateTime) + // Return an ISO 8601 formatted string, also known as a Round-trip date/time pattern + // https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx#Anchor_8 + // For example: 2009-06-15T13:45:30.0000000 return ((DateTime)obj).ToString ("o"); else if (obj is List) return String.Join(",", (obj as List).ToArray()); diff --git a/modules/swagger-codegen/src/main/resources/csharp/ApiClient.mustache b/modules/swagger-codegen/src/main/resources/csharp/ApiClient.mustache index cbbcf1e743f9..172e6bc627ad 100644 --- a/modules/swagger-codegen/src/main/resources/csharp/ApiClient.mustache +++ b/modules/swagger-codegen/src/main/resources/csharp/ApiClient.mustache @@ -156,6 +156,9 @@ namespace {{packageName}}.Client public string ParameterToString(object obj) { if (obj is DateTime) + // Return an ISO 8601 formatted string, also known as a Round-trip date/time pattern + // https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx#Anchor_8 + // For example: 2009-06-15T13:45:30.0000000 return ((DateTime)obj).ToString ("o"); else if (obj is IList) { From 74d80289dd24e5c7aad799d8b20c8ed47a6b8885 Mon Sep 17 00:00:00 2001 From: Jeff Kwan Date: Thu, 10 Dec 2015 20:28:44 -0500 Subject: [PATCH 45/71] Add a unit test for the datetime serialization --- .../src/main/csharp/IO/Swagger/Client/ApiClient.cs | 5 ++++- .../petstore/csharp/SwaggerClientTest/TestApiClient.cs | 5 +++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Client/ApiClient.cs b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Client/ApiClient.cs index 07b31cbf8174..1dc978443a33 100644 --- a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Client/ApiClient.cs +++ b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Client/ApiClient.cs @@ -156,7 +156,10 @@ namespace IO.Swagger.Client public string ParameterToString(object obj) { if (obj is DateTime) - return ((DateTime)obj).ToString ("u"); + // Return an ISO 8601 formatted string, also known as a Round-trip date/time pattern + // https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx#Anchor_8 + // For example: 2009-06-15T13:45:30.0000000 + return ((DateTime)obj).ToString ("o"); else if (obj is IList) { string flattenString = ""; diff --git a/samples/client/petstore/csharp/SwaggerClientTest/TestApiClient.cs b/samples/client/petstore/csharp/SwaggerClientTest/TestApiClient.cs index ff81f6b7c76f..3e9bbfb12d28 100644 --- a/samples/client/petstore/csharp/SwaggerClientTest/TestApiClient.cs +++ b/samples/client/petstore/csharp/SwaggerClientTest/TestApiClient.cs @@ -19,6 +19,11 @@ namespace SwaggerClient.TestApiClient // test array of int List numList = new List(new int[] {1, 37}); Assert.AreEqual("1,37", api.ParameterToString (numList)); + + // test datetime + DateTime date = DateTime.Parse("2008-04-10T13:30:00.0000000Z", null, System.Globalization.DateTimeStyles.RoundtripKind); + Assert.AreEqual("2008-04-10T13:30:00.0000000Z", api.ParameterToString (date)); + } } } From ca26608b28bf2e229cfac3ee68fc8494f03421c3 Mon Sep 17 00:00:00 2001 From: Jeff Kwan Date: Thu, 10 Dec 2015 20:42:30 -0500 Subject: [PATCH 46/71] Add some tests for time zones --- .../csharp/SwaggerClientTest/TestApiClient.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/samples/client/petstore/csharp/SwaggerClientTest/TestApiClient.cs b/samples/client/petstore/csharp/SwaggerClientTest/TestApiClient.cs index 3e9bbfb12d28..5b9b27ce6569 100644 --- a/samples/client/petstore/csharp/SwaggerClientTest/TestApiClient.cs +++ b/samples/client/petstore/csharp/SwaggerClientTest/TestApiClient.cs @@ -21,8 +21,16 @@ namespace SwaggerClient.TestApiClient Assert.AreEqual("1,37", api.ParameterToString (numList)); // test datetime - DateTime date = DateTime.Parse("2008-04-10T13:30:00.0000000Z", null, System.Globalization.DateTimeStyles.RoundtripKind); - Assert.AreEqual("2008-04-10T13:30:00.0000000Z", api.ParameterToString (date)); + DateTime dateUtc = DateTime.Parse("2008-04-10T13:30:00.0000000z", null, System.Globalization.DateTimeStyles.RoundtripKind); + Assert.AreEqual("2008-04-10T13:30:00.0000000Z", api.ParameterToString (dateUtc)); + + // test datetime with no timezone + DateTime dateWithNoTz = DateTime.Parse("2008-04-10T13:30:00.000", null, System.Globalization.DateTimeStyles.RoundtripKind); + Assert.AreEqual("2008-04-10T13:30:00.0000000", api.ParameterToString (dateWithNoTz)); + + // test datetime with a time zone + DateTime dateWithTz = DateTime.Parse("2008-04-10T13:30:00.0000000-04:00", null, System.Globalization.DateTimeStyles.RoundtripKind); + Assert.AreEqual("2008-04-10T13:30:00.0000000-04:00", api.ParameterToString (dateWithTz)); } } From 3acb5d60a097cc6c06ca0ce0b5713109d5084d51 Mon Sep 17 00:00:00 2001 From: wing328 Date: Fri, 11 Dec 2015 14:36:28 +0800 Subject: [PATCH 47/71] add swgger client profiling for php --- .../php/swagger_client_profiling.output | 31 +++++++ .../petstore/php/swagger_client_profiling.php | 80 +++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 samples/client/petstore/php/swagger_client_profiling.output create mode 100644 samples/client/petstore/php/swagger_client_profiling.php diff --git a/samples/client/petstore/php/swagger_client_profiling.output b/samples/client/petstore/php/swagger_client_profiling.output new file mode 100644 index 000000000000..487dd36f4dac --- /dev/null +++ b/samples/client/petstore/php/swagger_client_profiling.output @@ -0,0 +1,31 @@ +0: NEW PETAPI => 0.050940 +0: ADD PET => 0.901768 +0: GET PET => 0.368627 +0: UPDATE PET => 0.366801 +0: DELETE PET => 0.368657 +1: NEW PETAPI => 0.000020 +1: ADD PET => 0.365229 +1: GET PET => 0.366909 +1: UPDATE PET => 0.366458 +1: DELETE PET => 0.365904 +2: NEW PETAPI => 0.000018 +2: ADD PET => 0.367664 +2: GET PET => 0.364671 +2: UPDATE PET => 0.365267 +2: DELETE PET => 0.366162 +3: NEW PETAPI => 0.000018 +3: ADD PET => 0.364907 +3: GET PET => 0.364156 +3: UPDATE PET => 0.366996 +3: DELETE PET => 0.366705 +4: NEW PETAPI => 0.000018 +4: ADD PET => 0.370373 +4: GET PET => 0.365455 +4: UPDATE PET => 0.365915 +4: DELETE PET => 0.368835 +5: NEW PETAPI => 0.000017 +5: ADD PET => 0.367148 +5: GET PET => 0.368994 +5: UPDATE PET => 0.368870 +5: DELETE PET => 0.367270 +6: FINISH diff --git a/samples/client/petstore/php/swagger_client_profiling.php b/samples/client/petstore/php/swagger_client_profiling.php new file mode 100644 index 000000000000..20a3d6b6bf58 --- /dev/null +++ b/samples/client/petstore/php/swagger_client_profiling.php @@ -0,0 +1,80 @@ + %f\n", $prof_names[$i], $prof_timing[$i+1]-$prof_timing[$i]); + } + echo "{$prof_names[$size-1]}\n"; +} + +$counter = 5; // run 5 times by default +$new_pet_id = 50001; // ID of pet that needs to be fetched + +for ($x = 0; $x <= $counter; $x++) { + try { + prof_flag("$x: NEW PETAPI"); + $pet_api = new Swagger\Client\Api\PetApi(); + + // ~~~ ADD PET ~~~ + prof_flag("$x: ADD PET"); + // add pet (post json) + $new_pet = new Swagger\Client\Model\Pet; + $new_pet->setId($new_pet_id); + $new_pet->setName("profiler"); + $new_pet->setStatus("available"); + $new_pet->setPhotoUrls(array("http://profiler.com")); + // new tag + $tag= new Swagger\Client\Model\Tag; + $tag->setId($new_pet_id); // use the same id as pet + $tag->setName("profile tag 1"); + // new category + $category = new Swagger\Client\Model\Category; + $category->setId($new_pet_id); // use the same id as pet + $category->setName("profile category 1"); + + $new_pet->setTags(array($tag)); + $new_pet->setCategory($category); + + // add a new pet (model) + $add_response = $pet_api->addPet($new_pet); + + // ~~~ GET PET ~~~ + prof_flag("$x: GET PET"); + $response = $pet_api->getPetById($new_pet_id); + + // ~~~ UPDATE PET WITH FORM ~~~ + prof_flag("$x: UPDATE PET"); + $response = $pet_api->updatePetWithForm($new_pet_id, "new profiler", "sold"); + + // ~~~ DELETE PET ~~~ + prof_flag("$x: DELETE PET"); + $response = $pet_api->deletePet($new_pet_id); + + } catch (Swagger\Client\ApiException $e) { + echo 'Caught exception: ', $e->getMessage(), "\n"; + echo 'HTTP response headers: ', print_r($e->getResponseHeaders(), true), "\n"; + echo 'HTTP response body: ', print_r($e->getResponseBody(), true), "\n"; + echo 'HTTP status code: ', $e->getCode(), "\n"; + } + +} + +prof_flag("$x: FINISH"); +prof_print(); + + From 4272e9c027899f8ac970c3b3aa494975eb6cbd36 Mon Sep 17 00:00:00 2001 From: xhh Date: Fri, 11 Dec 2015 23:24:19 +0800 Subject: [PATCH 48/71] Add profiling script and results for Ruby Petstore sample --- .../petstore/ruby/petstore_profiling.output | 315 ++++++++++++++++++ .../petstore/ruby/petstore_profiling.rb | 75 +++++ 2 files changed, 390 insertions(+) create mode 100644 samples/client/petstore/ruby/petstore_profiling.output create mode 100644 samples/client/petstore/ruby/petstore_profiling.rb diff --git a/samples/client/petstore/ruby/petstore_profiling.output b/samples/client/petstore/ruby/petstore_profiling.output new file mode 100644 index 000000000000..36750b5e2b9e --- /dev/null +++ b/samples/client/petstore/ruby/petstore_profiling.output @@ -0,0 +1,315 @@ +Measure Mode: wall_time +Thread ID: 70329221636600 +Fiber ID: 70329234076680 +Total: 10.998497 +Sort by: self_time + + %self total self wait child calls name + 99.20 10.920 10.911 0.000 0.010 20 #easy_perform + 0.05 0.005 0.005 0.000 0.000 1392 Symbol#to_s + 0.04 0.019 0.005 0.000 0.015 268 Ethon::Curls::Options#set_option + 0.02 0.003 0.003 0.000 0.000 718 Ethon::Easy::Operations#handle + 0.02 0.003 0.003 0.000 0.000 657 String#downcase + 0.02 0.003 0.003 0.000 0.000 658 FFI::Enum#to_native + 0.02 0.003 0.003 0.000 0.000 678 FFI::Enum#from_native + 0.02 0.029 0.002 0.000 0.027 200 *Proc#call + 0.02 0.034 0.002 0.000 0.032 210 *Array#each + 0.02 0.014 0.002 0.000 0.012 309 *Class#new + 0.02 0.004 0.002 0.000 0.003 390 #easy_getinfo + 0.02 0.002 0.002 0.000 0.000 175 Typhoeus::EasyFactory#renamed_options + 0.01 0.001 0.001 0.000 0.000 744 Kernel#respond_to? + 0.01 0.003 0.001 0.000 0.002 201 *#method_missing + 0.01 0.006 0.001 0.000 0.005 75 Hash#each + 0.01 0.020 0.001 0.000 0.019 56 *Hash#each_pair + 0.01 0.001 0.001 0.000 0.000 430 Symbol#to_sym + 0.01 0.004 0.001 0.000 0.003 210 Ethon::Curls::Infos#get_info_double + 0.01 0.003 0.001 0.000 0.002 175 *Array#map + 0.01 0.001 0.001 0.000 0.000 268 Ethon::Curls::Options#easy_options + 0.01 0.001 0.001 0.000 0.000 201 #instance + 0.01 0.001 0.001 0.000 0.000 420 Ethon::Curls::Infos#double_ptr + 0.01 0.002 0.001 0.000 0.001 250 FFI::Pointer#read_string + 0.01 0.001 0.001 0.000 0.000 80 Hash#initialize_copy + 0.01 0.001 0.001 0.000 0.000 240 Typhoeus::Response::Header#set_value + 0.01 0.001 0.001 0.000 0.000 656 Kernel#is_a? + 0.01 0.001 0.001 0.000 0.000 42 String#gsub + 0.01 0.003 0.001 0.000 0.002 120 Ethon::Curls::Infos#get_info_long + 0.01 0.004 0.001 0.000 0.004 120 Typhoeus::Response::Header#process_line + 0.01 0.001 0.001 0.000 0.001 85 #easy_setopt_string + 0.01 0.001 0.001 0.000 0.000 140 String#split + 0.01 0.001 0.001 0.000 0.000 485 Kernel#nil? + 0.01 0.001 0.001 0.000 0.000 240 Ethon::Curls::Infos#long_ptr + 0.01 0.001 0.001 0.000 0.000 42 #easy_setopt_callback + 0.01 0.006 0.001 0.000 0.006 20 Petstore::ApiClient#build_request + 0.00 0.001 0.000 0.000 0.001 90 #easy_setopt_long + 0.00 0.000 0.000 0.000 0.000 170 FFI::AbstractMemory#get_bytes + 0.00 0.001 0.000 0.000 0.000 30 #informations_to_mirror + 0.00 0.002 0.000 0.000 0.002 120 Typhoeus::Response::Header#process_pair + 0.00 0.002 0.000 0.000 0.002 60 Ethon::Curls::Infos#get_info_string + 0.00 0.000 0.000 0.000 0.000 190 String#to_s + 0.00 0.000 0.000 0.000 0.000 130 Kernel#class + 0.00 0.000 0.000 0.000 0.000 240 String#strip + 0.00 0.001 0.000 0.000 0.001 42 Mutex#synchronize + 0.00 0.000 0.000 0.000 0.000 268 Hash#include? + 0.00 0.000 0.000 0.000 0.000 36 String#sub + 0.00 0.001 0.000 0.000 0.001 21 FFI::AutoPointer#initialize + 0.00 0.000 0.000 0.000 0.000 400 Array#include? + 0.00 10.941 0.000 0.000 10.941 20 Ethon::Easy::Operations#perform + 0.00 0.000 0.000 0.000 0.000 185 Integer#to_i + 0.00 0.006 0.000 0.000 0.006 21 Ethon::Easy::Callbacks#set_callbacks + 0.00 0.001 0.000 0.000 0.001 80 Ethon::Easy::Header#compose_header + 0.00 0.000 0.000 0.000 0.000 210 FFI::AbstractMemory#read_double + 0.00 0.001 0.000 0.000 0.000 90 #find_type + 0.00 0.001 0.000 0.000 0.001 90 #type_size + 0.00 0.002 0.000 0.000 0.001 30 Ethon::Easy::Informations#httpauth_avail + 0.00 0.000 0.000 0.000 0.000 80 #slist_append + 0.00 0.001 0.000 0.000 0.001 85 Kernel#initialize_dup + 0.00 0.000 0.000 0.000 0.000 330 Hash#has_key? + 0.00 10.993 0.000 0.000 10.992 20 Petstore::ApiClient#call_api + 0.00 0.000 0.000 0.000 0.000 80 String#encode + 0.00 0.001 0.000 0.000 0.000 20 Petstore::Configuration#auth_settings + 0.00 0.001 0.000 0.000 0.000 140 Typhoeus::Response::Informations#response_code + 0.00 0.000 0.000 0.000 0.000 65 #attribute_map + 0.00 0.000 0.000 0.000 0.000 35 Petstore::ApiClient#json_mime? + 0.00 0.001 0.000 0.000 0.000 85 Ethon::Easy::Http::Actionable#form + 0.00 0.000 0.000 0.000 0.000 45 Hash#keys + 0.00 0.023 0.000 0.000 0.022 20 Ethon::Easy::Http::Actionable#setup + 0.00 0.002 0.000 0.000 0.001 80 Typhoeus::EasyFactory#easy + 0.00 0.001 0.000 0.000 0.001 20 Typhoeus::Request::Callbacks#execute_callbacks + 0.00 0.001 0.000 0.000 0.000 40 Hash#merge + 0.00 0.001 0.000 0.000 0.000 80 Ethon::Easy::Util#escape_zero_byte + 0.00 0.000 0.000 0.000 0.000 120 Ethon::Curls::Infos#string_ptr + 0.00 0.001 0.000 0.000 0.000 50 Enumerable#find + 0.00 0.000 0.000 0.000 0.000 80 FFI::AbstractMemory#get_string + 0.00 0.000 0.000 0.000 0.000 80 Typhoeus::Request::Responseable#response + 0.00 0.000 0.000 0.000 0.000 120 FFI::AbstractMemory#read_long + 0.00 0.000 0.000 0.000 0.000 120 Hash#[]= + 0.00 0.001 0.000 0.000 0.001 40 Typhoeus::Response::Status#success? + 0.00 10.998 0.000 0.000 10.998 5 PetstoreProfiling#call_apis + 0.00 0.000 0.000 0.000 0.000 20 #easy_reset + 0.00 0.007 0.000 0.000 0.007 25 Typhoeus::Response::Informations#headers + 0.00 0.000 0.000 0.000 0.000 90 Fixnum#<< + 0.00 0.001 0.000 0.000 0.001 20 Petstore::ApiClient#build_request_url + 0.00 0.032 0.000 0.000 0.031 20 Typhoeus::EasyFactory#get + 0.00 0.001 0.000 0.000 0.001 45 Kernel#dup + 0.00 0.000 0.000 0.000 0.000 21 #easy_setopt_debug_callback + 0.00 0.016 0.000 0.000 0.016 30 #from_easy + 0.00 0.000 0.000 0.000 0.000 20 String#lines + 0.00 0.001 0.000 0.000 0.000 20 Typhoeus::Request#set_defaults + 0.00 0.006 0.000 0.000 0.006 20 Typhoeus::Response::Header#initialize + 0.00 0.000 0.000 0.000 0.000 40 Typhoeus::Request::Callbacks::Types#on_complete + 0.00 0.000 0.000 0.000 0.000 120 Symbol#to_proc + 0.00 0.001 0.000 0.000 0.000 20 Typhoeus::EasyFactory#set_callback + 0.00 10.974 0.000 0.000 10.973 20 Typhoeus::Request::Operations#run + 0.00 0.001 0.000 0.000 0.001 60 *Petstore::BaseObject#_to_hash + 0.00 0.000 0.000 0.000 0.000 90 FFI::Type#size + 0.00 0.000 0.000 0.000 0.000 60 FFI::AbstractMemory#read_pointer + 0.00 0.002 0.000 0.000 0.002 20 Typhoeus::Request::Operations#finish + 0.00 0.001 0.000 0.000 0.000 21 URI::Escape#escape + 0.00 0.000 0.000 0.000 0.000 40 Typhoeus::Request::Callbacks::Types#on_success + 0.00 0.000 0.000 0.000 0.000 22 Ethon::Loggable#logger + 0.00 0.000 0.000 0.000 0.000 65 Typhoeus::Response#mock + 0.00 0.006 0.000 0.000 0.006 20 Ethon::Easy#reset + 0.00 0.001 0.000 0.000 0.000 30 #easy_setopt_ffipointer + 0.00 0.001 0.000 0.000 0.001 5 JSON::Ext::Generator::GeneratorMethods::Hash#to_json + 0.00 3.494 0.000 0.000 3.494 5 Petstore::PetApi#get_pet_by_id_with_http_info + 0.00 0.000 0.000 0.000 0.000 160 Kernel#block_given? + 0.00 3.220 0.000 0.000 3.219 5 Petstore::PetApi#update_pet_with_form_with_http_info + 0.00 0.001 0.000 0.000 0.001 30 Ethon::Easy::Informations#effective_url + 0.00 0.006 0.000 0.000 0.006 20 Typhoeus::Response::Header#parse + 0.00 10.975 0.000 0.000 10.975 20 Typhoeus::Request::Before#run + 0.00 0.011 0.000 0.000 0.011 20 Ethon::Easy#mirror + 0.00 0.000 0.000 0.000 0.000 40 #easies + 0.00 0.000 0.000 0.000 0.000 40 Typhoeus::EasyFactory#sanitize_timeout! + 0.00 0.000 0.000 0.000 0.000 5 JSON::Ext::Parser#parse + 0.00 0.000 0.000 0.000 0.000 50 String#to_sym + 0.00 0.000 0.000 0.000 0.000 70 Hash#fetch + 0.00 0.001 0.000 0.000 0.001 20 Typhoeus::Request#initialize + 0.00 0.005 0.000 0.000 0.005 20 Typhoeus::EasyFactory#sanitize + 0.00 0.000 0.000 0.000 0.000 21 URI::RFC2396_Parser#escape + 0.00 0.001 0.000 0.000 0.001 30 Ethon::Easy::Informations#total_time + 0.00 0.001 0.000 0.000 0.001 30 Ethon::Easy::Informations#appconnect_time + 0.00 2.141 0.000 0.000 2.141 5 Petstore::PetApi#delete_pet_with_http_info + 0.00 0.001 0.000 0.000 0.000 20 Petstore::ApiClient#select_header_accept + 0.00 0.000 0.000 0.000 0.000 30 Enumerable#inject + 0.00 0.000 0.000 0.000 0.000 80 Integer#chr + 0.00 0.000 0.000 0.000 0.000 90 Fixnum#< + 0.00 10.974 0.000 0.000 10.974 20 Typhoeus::Request::BlockConnection#run + 0.00 2.143 0.000 0.000 2.143 5 Petstore::PetApi#add_pet_with_http_info + 0.00 0.000 0.000 0.000 0.000 21 Logger#add + 0.00 0.020 0.000 0.000 0.020 20 Ethon::Easy::ResponseCallbacks#complete + 0.00 0.000 0.000 0.000 0.000 21 Logger#debug + 0.00 10.975 0.000 0.000 10.974 20 Typhoeus::Request::Stubbable#run + 0.00 0.004 0.000 0.000 0.004 20 Ethon::Easy::Header#headers= + 0.00 0.000 0.000 0.000 0.000 20 Typhoeus::Request::Cacheable#response= + 0.00 0.001 0.000 0.000 0.001 50 *Petstore::BaseObject#_deserialize + 0.00 0.000 0.000 0.000 0.000 35 Module#const_get + 0.00 0.000 0.000 0.000 0.000 20 Ethon::Easy::Http::Actionable#params + 0.00 0.003 0.000 0.000 0.003 10 Ethon::Easy::Http::Postable#set_form + 0.00 0.000 0.000 0.000 0.000 50 Symbol#=~ + 0.00 0.001 0.000 0.000 0.001 30 Ethon::Easy::Informations#pretransfer_time + 0.00 0.000 0.000 0.000 0.000 30 Typhoeus::Response#initialize + 0.00 0.000 0.000 0.000 0.000 10 Petstore::Pet#initialize + 0.00 0.000 0.000 0.000 0.000 20 Petstore::ApiClient#select_header_content_type + 0.00 0.002 0.000 0.000 0.002 20 Ethon::Easy::Options#nosignal= + 0.00 0.001 0.000 0.000 0.001 20 Ethon::Easy::Http::Actionable#initialize + 0.00 0.000 0.000 0.000 0.000 21 #define_finalizer + 0.00 0.002 0.000 0.000 0.001 20 Ethon::Easy::Http#fabricate + 0.00 0.001 0.000 0.000 0.001 30 Ethon::Easy::Informations#primary_ip + 0.00 0.000 0.000 0.000 0.000 119 NilClass#nil? + 0.00 0.001 0.000 0.000 0.001 30 Ethon::Easy::Informations#redirect_time + 0.00 0.001 0.000 0.000 0.001 30 Ethon::Easy::Informations#starttransfer_time + 0.00 0.000 0.000 0.000 0.000 20 Symbol#downcase + 0.00 0.000 0.000 0.000 0.000 21 Kernel#method + 0.00 0.000 0.000 0.000 0.000 20 Petstore::Configuration#api_key_with_prefix + 0.00 0.000 0.000 0.000 0.000 25 #attribute_map + 0.00 10.974 0.000 0.000 10.974 20 Typhoeus::Request::Cacheable#run + 0.00 0.000 0.000 0.000 0.000 20 Typhoeus::Request::Callbacks::Types#on_headers + 0.00 0.001 0.000 0.000 0.001 30 Ethon::Easy::Informations#namelookup_time + 0.00 0.001 0.000 0.000 0.001 30 Ethon::Easy::Informations#connect_time + 0.00 0.001 0.000 0.000 0.001 30 Ethon::Easy::Informations#request_size + 0.00 0.000 0.000 0.000 0.000 21 String#force_encoding + 0.00 0.000 0.000 0.000 0.000 20 #before + 0.00 0.000 0.000 0.000 0.000 40 Typhoeus::Response::Informations#return_code + 0.00 0.000 0.000 0.000 0.000 30 Ethon::Easy::Mirror#initialize + 0.00 0.000 0.000 0.000 0.000 15 Petstore::ApiClient#build_request_body + 0.00 0.001 0.000 0.000 0.001 30 Ethon::Easy::Informations#redirect_count + 0.00 0.025 0.000 0.000 0.025 20 Ethon::Easy::Http#http_request + 0.00 0.001 0.000 0.000 0.001 30 Ethon::Easy::Informations#response_code + 0.00 0.000 0.000 0.000 0.000 50 Ethon::Easy::Http::Actionable#query_options + 0.00 0.000 0.000 0.000 0.000 25 #attribute_map + 0.00 0.000 0.000 0.000 0.000 25 NilClass#to_s + 0.00 0.007 0.000 0.000 0.007 20 #release + 0.00 0.000 0.000 0.000 0.000 20 Ethon::Easy::ResponseCallbacks#on_headers + 0.00 0.000 0.000 0.000 0.000 20 #response_for + 0.00 0.001 0.000 0.000 0.001 20 Ethon::Easy::Http::Actionable#parse_options + 0.00 0.000 0.000 0.000 0.000 35 Hash#delete + 0.00 0.000 0.000 0.000 0.000 45 Typhoeus::Response::Informations#response_headers + 0.00 0.000 0.000 0.000 0.000 20 #easy_escape + 0.00 0.000 0.000 0.000 0.000 21 FFI::AutoPointer::Releaser#initialize + 0.00 0.000 0.000 0.000 0.000 21 Ethon::Easy::Callbacks#header_write_callback + 0.00 0.000 0.000 0.000 0.000 21 Ethon::Easy::DebugInfo#initialize + 0.00 0.000 0.000 0.000 0.000 20 Typhoeus::EasyFactory#initialize + 0.00 0.000 0.000 0.000 0.000 20 Typhoeus::Request::Memoizable#response= + 0.00 0.000 0.000 0.000 0.000 105 Module#=== + 0.00 0.000 0.000 0.000 0.000 80 String#include? + 0.00 0.000 0.000 0.000 0.000 21 Ethon::Easy::Callbacks#body_write_callback + 0.00 0.000 0.000 0.000 0.000 16 Array#join + 0.00 0.000 0.000 0.000 0.000 20 #find_by + 0.00 0.005 0.000 0.000 0.005 5 Petstore::ApiClient#deserialize + 0.00 0.000 0.000 0.000 0.000 30 Regexp#=== + 0.00 0.006 0.000 0.000 0.006 10 Ethon::Easy::ResponseCallbacks#headers + 0.00 0.000 0.000 0.000 0.000 21 Ethon::Easy::Callbacks#debug_callback + 0.00 0.000 0.000 0.000 0.000 20 Ethon::Easy::ResponseCallbacks#on_complete + 0.00 0.002 0.000 0.000 0.002 20 Ethon::Easy::Options#url= + 0.00 0.000 0.000 0.000 0.000 84 Kernel#kind_of? + 0.00 0.000 0.000 0.000 0.000 40 Typhoeus::Request::Cacheable#cacheable? + 0.00 0.017 0.000 0.000 0.017 21 Ethon::Easy#set_attributes + 0.00 0.000 0.000 0.000 0.000 20 Module#const_defined? + 0.00 0.001 0.000 0.000 0.001 20 #get + 0.00 0.000 0.000 0.000 0.000 20 #pid + 0.00 0.000 0.000 0.000 0.000 40 String#bytesize + 0.00 0.000 0.000 0.000 0.000 20 Ethon::Easy::Params#initialize + 0.00 0.000 0.000 0.000 0.000 20 Kernel#lambda + 0.00 0.000 0.000 0.000 0.000 20 String#capitalize + 0.00 0.000 0.000 0.000 0.000 25 Ethon::Easy::Queryable#query_pairs + 0.00 0.000 0.000 0.000 0.000 195 Symbol#=== + 0.00 0.000 0.000 0.000 0.000 20 Ethon::Easy::Form#initialize + 0.00 0.000 0.000 0.000 0.000 13 FFI::MemoryPointer#initialize + 0.00 0.000 0.000 0.000 0.000 105 Hash#key? + 0.00 0.000 0.000 0.000 0.000 20 Ethon::Easy#escape + 0.00 0.000 0.000 0.000 0.000 20 #all + 0.00 0.000 0.000 0.000 0.000 10 Typhoeus::Request::Callbacks#execute_headers_callbacks + 0.00 0.000 0.000 0.000 0.000 20 Typhoeus::Response::Header#set_default_proc_on + 0.00 0.000 0.000 0.000 0.000 15 Hash#update + 0.00 0.000 0.000 0.000 0.000 60 FFI::Pointer#null? + 0.00 0.001 0.000 0.000 0.001 20 Ethon::Easy::Options#sslcert= + 0.00 0.001 0.000 0.000 0.001 20 Ethon::Easy::Queryable#to_s + 0.00 0.000 0.000 0.000 0.000 55 Ethon::Easy::Queryable#empty? + 0.00 0.000 0.000 0.000 0.000 20 Hash#default_proc= + 0.00 0.000 0.000 0.000 0.000 10 Petstore::Category#initialize + 0.00 0.000 0.000 0.000 0.000 10 Petstore::Tag#initialize + 0.00 0.000 0.000 0.000 0.000 21 FFI::Pointer#initialize + 0.00 0.002 0.000 0.000 0.001 20 Ethon::Easy::Options#verbose= + 0.00 0.002 0.000 0.000 0.002 20 Ethon::Easy::Options#maxredirs= + 0.00 0.001 0.000 0.000 0.001 20 Ethon::Easy::Options#sslkey= + 0.00 0.000 0.000 0.000 0.000 20 Array#pop + 0.00 0.000 0.000 0.000 0.000 21 FFI::Pointer#type_size + 0.00 0.000 0.000 0.000 0.000 20 Ethon::Easy::Http::Actionable#url + 0.00 0.000 0.000 0.000 0.000 20 Typhoeus::Request::BlockConnection#blocked? + 0.00 0.002 0.000 0.000 0.002 20 Ethon::Easy::Options#ssl_verifypeer= + 0.00 0.000 0.000 0.000 0.000 20 Ethon::Easy::Http::Actionable#options + 0.00 0.000 0.000 0.000 0.000 10 Ethon::Easy::ResponseCallbacks#body + 0.00 0.000 0.000 0.000 0.000 10 Petstore::Pet#status= + 0.00 0.001 0.000 0.000 0.001 20 Ethon::Easy::Options#cainfo= + 0.00 0.000 0.000 0.000 0.000 30 Array#last + 0.00 0.001 0.000 0.000 0.001 20 Petstore::ApiClient#update_params_for_auth! + 0.00 0.003 0.000 0.000 0.003 5 Petstore::ApiClient#convert_to_type + 0.00 10.998 0.000 0.000 10.998 1 PetstoreProfiling#run + 0.00 0.012 0.000 0.000 0.011 10 Ethon::Easy::Http::Post#setup + 0.00 0.000 0.000 0.000 0.000 5 JSON::Ext::Parser#initialize + 0.00 0.000 0.000 0.000 0.000 20 Typhoeus::Request::Memoizable#memoizable? + 0.00 0.000 0.000 0.000 0.000 20 Typhoeus::Response::Header#raw + 0.00 0.002 0.000 0.000 0.002 5 Petstore::ApiClient#object_to_http_body + 0.00 0.000 0.000 0.000 0.000 20 Typhoeus::Request::Responseable#response= + 0.00 0.000 0.000 0.000 0.000 15 Fixnum#to_s + 0.00 0.001 0.000 0.000 0.001 15 *Petstore::BaseObject#to_hash + 0.00 0.000 0.000 0.000 0.000 10 Array#any? + 0.00 0.000 0.000 0.000 0.000 10 Ethon::Easy::Queryable#build_query_pairs + 0.00 0.000 0.000 0.000 0.000 1 #easy_init + 0.00 0.000 0.000 0.000 0.000 10 Ethon::Easy::Queryable#pairs_for + 0.00 0.001 0.000 0.000 0.000 5 Petstore::PetApi#initialize + 0.00 0.000 0.000 0.000 0.000 10 Array#compact + 0.00 0.003 0.000 0.000 0.002 15 *Petstore::BaseObject#build_from_hash + 0.00 0.000 0.000 0.000 0.000 20 Typhoeus::Request::Streamable#streaming? + 0.00 0.000 0.000 0.000 0.000 10 Ethon::Easy::Http::Actionable#params_encoding + 0.00 0.000 0.000 0.000 0.000 10 FFI::AbstractMemory#put_bytes + 0.00 3.494 0.000 0.000 3.494 5 Petstore::PetApi#get_pet_by_id + 0.00 0.000 0.000 0.000 0.000 20 Proc#to_proc + 0.00 0.000 0.000 0.000 0.000 5 Petstore::Configuration#api_client + 0.00 0.006 0.000 0.000 0.006 5 Ethon::Easy::Http::Delete#setup + 0.00 0.001 0.000 0.000 0.001 10 Ethon::Easy::Options#postfieldsize= + 0.00 0.001 0.000 0.000 0.001 10 Ethon::Easy::Options#copypostfields= + 0.00 0.005 0.000 0.000 0.005 5 Ethon::Easy::Http::Get#setup + 0.00 2.143 0.000 0.000 2.143 5 Petstore::PetApi#add_pet + 0.00 0.000 0.000 0.000 0.000 20 #free + 0.00 0.000 0.000 0.000 0.000 1 Petstore::Configuration#initialize + 0.00 2.141 0.000 0.000 2.141 5 Petstore::PetApi#delete_pet + 0.00 0.000 0.000 0.000 0.000 20 Kernel#Array + 0.00 0.000 0.000 0.000 0.000 45 Kernel#respond_to_missing? + 0.00 0.000 0.000 0.000 0.000 1 #global_init + 0.00 0.000 0.000 0.000 0.000 5 #swagger_types + 0.00 0.001 0.000 0.000 0.001 5 Petstore::ApiClient#object_to_hash + 0.00 0.000 0.000 0.000 0.000 2 Logger#initialize + 0.00 0.000 0.000 0.000 0.000 10 Ethon::Easy::Form#multipart? + 0.00 0.000 0.000 0.000 0.000 5 JSON::Ext::Generator::State#initialize_copy + 0.00 0.000 0.000 0.000 0.000 2 MonitorMixin#initialize + 0.00 3.220 0.000 0.000 3.220 5 Petstore::PetApi#update_pet_with_form + 0.00 0.000 0.000 0.000 0.000 5 #swagger_types + 0.00 0.000 0.000 0.000 0.000 1 Petstore::ApiClient#initialize + 0.00 0.003 0.000 0.000 0.003 5 Kernel#tap + 0.00 0.000 0.000 0.000 0.000 5 JSON#parse + 0.00 0.000 0.000 0.000 0.000 5 Ethon::Easy::Options#customrequest= + 0.00 0.000 0.000 0.000 0.000 5 Ethon::Easy::Queryable#recursively_generate_pairs + 0.00 0.000 0.000 0.000 0.000 5 #swagger_types + 0.00 0.000 0.000 0.000 0.000 2 Logger::LogDevice#initialize + 0.00 10.998 0.000 0.000 10.998 1 Integer#times + 0.00 0.000 0.000 0.000 0.000 1 Petstore::Configuration#base_url + 0.00 0.000 0.000 0.000 0.000 2 MonitorMixin#mon_initialize + 0.00 0.000 0.000 0.000 0.000 35 String#=== + 0.00 0.000 0.000 0.000 0.000 3 Kernel#proc + 0.00 0.000 0.000 0.000 0.000 5 Typhoeus::Response::Informations#response_body + 0.00 0.000 0.000 0.000 0.000 10 Kernel#=== + 0.00 0.001 0.000 0.000 0.001 1 Ethon::Easy#initialize + 0.00 0.000 0.000 0.000 0.000 5 Ethon::Easy::Queryable#encode_hash_pairs + 0.00 0.000 0.000 0.000 0.000 5 String#encoding + 0.00 0.000 0.000 0.000 0.000 5 Array#first + 0.00 0.000 0.000 0.000 0.000 5 Hash#[] + 0.00 0.000 0.000 0.000 0.000 2 BasicObject#initialize + 0.00 0.000 0.000 0.000 0.000 1 Ethon::Loggable#default_logger + 0.00 0.000 0.000 0.000 0.000 2 Logger::Formatter#initialize + 0.00 0.000 0.000 0.000 0.000 1 #init + 0.00 0.000 0.000 0.000 0.000 2 Mutex#initialize + 0.00 0.000 0.000 0.000 0.000 1 Ethon::Loggable#rails_logger + 0.00 0.000 0.000 0.000 0.000 10 BasicObject#== + +* indicates recursively called methods diff --git a/samples/client/petstore/ruby/petstore_profiling.rb b/samples/client/petstore/ruby/petstore_profiling.rb new file mode 100644 index 000000000000..485bd40c0c76 --- /dev/null +++ b/samples/client/petstore/ruby/petstore_profiling.rb @@ -0,0 +1,75 @@ +# To run this profiling: +# gem install ruby-prof +# ruby -Ilib petstore_profiling.rb + +require 'petstore' +require 'ruby-prof' + +class PetstoreProfiling + attr_accessor :total, :new_pet_id, :output_file + + def initialize + @total = 5 + @new_pet_id = 50002 + @output_file = './petstore_profiling.output' + end + + def call_apis + pet_api = Petstore::PetApi.new + + ### ADD PET ### + pet = Petstore::Pet.new + pet.id = new_pet_id + pet.name = "profiler" + pet.status = "available" + pet.photo_urls = ["http://profiler.com"] + # new tag + tag= Petstore::Tag.new + tag.id = new_pet_id # use the same id as pet + tag.name = "profile tag 1" + # new category + category = Petstore::Category.new + category.id = new_pet_id # use the same id as pet + category.name = "profile category 1" + + pet.tags = [tag] + pet.category = category + + # add a new pet (model) + pet_api.add_pet(body: pet) + + ### GET PET ### + pet = pet_api.get_pet_by_id(new_pet_id) + + ### UPDATE PET WITH FORM ### + pet_api.update_pet_with_form(new_pet_id, name: 'new profiler', status: 'sold') + + ### DELETE PET ### + pet_api.delete_pet(new_pet_id) + rescue Petstore::ApiError => e + puts "Caught error: #{e.message}" + puts "HTTP response headers: #{e.response_headers}" + puts "HTTP response body: #{e.response_body}" + puts "HTTP status code: #{e.code}" + end + + def run + puts "Running profiling... (total: #{@total})" + + RubyProf.start + @total.times { call_apis } + result = RubyProf.stop + + printer = RubyProf::FlatPrinter.new(result) + File.open(@output_file, 'w') do |file| + printer.print(file) + end + + puts "Profiling results written to #{@output_file}" + end +end + +if __FILE__ == $0 + profiling = PetstoreProfiling.new + profiling.run +end From 8fc27b5f0c52161c861f2bb4b9d84ee29c7ec65c Mon Sep 17 00:00:00 2001 From: evigeant Date: Fri, 11 Dec 2015 12:57:05 -0500 Subject: [PATCH 49/71] Fixed a bug where the JSON.mustache file was removed from the jersey2 code generation --- .../java/io/swagger/codegen/languages/JavaClientCodegen.java | 2 ++ 1 file changed, 2 insertions(+) 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 06326d1e4dd2..1c03e6c9e6fd 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 @@ -251,6 +251,8 @@ public class JavaClientCodegen extends DefaultCodegen implements CodegenConfig { } else if ("retrofit".equals(getLibrary()) || "retrofit2".equals(getLibrary())) { supportingFiles.add(new SupportingFile("auth/OAuthOkHttpClient.mustache", authFolder, "OAuthOkHttpClient.java")); supportingFiles.add(new SupportingFile("CollectionFormats.mustache", invokerFolder, "CollectionFormats.java")); + } else if("jersey2".equals(getLibrary())) { + supportingFiles.add(new SupportingFile("JSON.mustache", invokerFolder, "JSON.java")); } } From e0582ae912732ae2849c081fa3af5486c8e7bfd3 Mon Sep 17 00:00:00 2001 From: Jeff Kwan Date: Fri, 11 Dec 2015 18:28:37 -0500 Subject: [PATCH 50/71] Added the ability to customize the DateTimeFormat Updated Configuration to have a DateTimeFormat Added Unit Tests for Configuration.DateTimeFormat Cleaned up namespaces in SwaggerClientTest Added an embedded resource for testing uploads --- .gitignore | 6 +- .../CsharpDotNet2/ApiClient.mustache | 7 +- .../CsharpDotNet2/Configuration.mustache | 35 ++++++++- .../main/resources/csharp/ApiClient.mustache | 7 +- .../resources/csharp/Configuration.mustache | 35 ++++++++- .../src/main/csharp/IO/Swagger/Api/PetApi.cs | 1 + .../main/csharp/IO/Swagger/Api/StoreApi.cs | 1 + .../src/main/csharp/IO/Swagger/Api/UserApi.cs | 1 + .../csharp/IO/Swagger/Client/ApiClient.cs | 7 +- .../csharp/IO/Swagger/Client/Configuration.cs | 35 ++++++++- .../main/csharp/IO/Swagger/Model/Category.cs | 4 ++ .../src/main/csharp/IO/Swagger/Model/Order.cs | 4 ++ .../src/main/csharp/IO/Swagger/Model/Pet.cs | 4 ++ .../src/main/csharp/IO/Swagger/Model/Tag.cs | 4 ++ .../src/main/csharp/IO/Swagger/Model/User.cs | 4 ++ .../SwaggerClientTest.csproj | 6 +- .../csharp/SwaggerClientTest/TestApiClient.cs | 68 +++++++++++++----- .../SwaggerClientTest/TestConfiguration.cs | 27 ++++++- .../csharp/SwaggerClientTest/TestPet.cs | 14 ++-- .../csharp/SwaggerClientTest/swagger-logo.png | Bin 0 -> 11917 bytes 20 files changed, 231 insertions(+), 39 deletions(-) create mode 100644 samples/client/petstore/csharp/SwaggerClientTest/swagger-logo.png diff --git a/.gitignore b/.gitignore index d55a8014a342..db34c76636c6 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ generated-sources/* generated-code/* *.swp *.swo +*.csproj.user /target /generated-files @@ -36,6 +37,9 @@ samples/client/petstore/objc/SwaggerClientTests/Pods samples/client/petstore/objc/SwaggerClientTests/SwaggerClient.xcworkspace samples/client/petstore/objc/SwaggerClientTests/Podfile.lock samples/server/petstore/nodejs/node_modules +samples/client/petstore/csharp/SwaggerClientTest/.vs +samples/client/petstore/csharp/SwaggerClientTest/obj +samples/client/petstore/csharp/SwaggerClientTest/bin target .idea .lib @@ -60,4 +64,4 @@ samples/client/petstore/python/.venv/ *.java~ *.pm~ *.xml~ -*.t~ \ No newline at end of file +*.t~ diff --git a/modules/swagger-codegen/src/main/resources/CsharpDotNet2/ApiClient.mustache b/modules/swagger-codegen/src/main/resources/CsharpDotNet2/ApiClient.mustache index 6d5e45c186e1..a428cdc3630f 100644 --- a/modules/swagger-codegen/src/main/resources/CsharpDotNet2/ApiClient.mustache +++ b/modules/swagger-codegen/src/main/resources/CsharpDotNet2/ApiClient.mustache @@ -134,7 +134,7 @@ namespace {{packageName}}.Client } /// - /// If parameter is DateTime, output in ISO8601 format. + /// If parameter is DateTime, output in a formatted string (default ISO 8601), customizable with Configuration.DateTime. /// If parameter is a list of string, join the list with ",". /// Otherwise just return the string. /// @@ -143,10 +143,11 @@ namespace {{packageName}}.Client public string ParameterToString(object obj) { if (obj is DateTime) - // Return an ISO 8601 formatted string, also known as a Round-trip date/time pattern + // Return a formatted date string - Can be customized with Configuration.DateTimeFormat + // Defaults to an ISO 8601, using the known as a Round-trip date/time pattern ("o") // https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx#Anchor_8 // For example: 2009-06-15T13:45:30.0000000 - return ((DateTime)obj).ToString ("o"); + return ((DateTime)obj).ToString (Configuration.DateTimeFormat); else if (obj is List) return String.Join(",", (obj as List).ToArray()); else diff --git a/modules/swagger-codegen/src/main/resources/CsharpDotNet2/Configuration.mustache b/modules/swagger-codegen/src/main/resources/CsharpDotNet2/Configuration.mustache index 67b07069e2f6..56f4e617556b 100644 --- a/modules/swagger-codegen/src/main/resources/CsharpDotNet2/Configuration.mustache +++ b/modules/swagger-codegen/src/main/resources/CsharpDotNet2/Configuration.mustache @@ -78,7 +78,40 @@ namespace {{packageName}}.Client _tempFolderPath = value + Path.DirectorySeparatorChar; } } - + + private const string ISO8601_DATETIME_FORMAT = "o"; + + private static string _dateTimeFormat = ISO8601_DATETIME_FORMAT; + + /// + /// Gets or sets the the date time format used when serializing in the ApiClient + /// By default, it's set to ISO 8601 - "o", for others see: + /// https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx + /// and https://msdn.microsoft.com/en-us/library/8kb3ddd4(v=vs.110).aspx + /// No validation is done to ensure that the string you're providing is valid + /// + /// The DateTimeFormat string + public static String DateTimeFormat + { + get + { + return _dateTimeFormat; + } + set + { + if (string.IsNullOrEmpty(value)) + { + // Never allow a blank or null string, go back to the default + _dateTimeFormat = ISO8601_DATETIME_FORMAT; + return; + } + + // Caution, no validation when you choose date time format other than ISO 8601 + // Take a look at the above links + _dateTimeFormat = value; + } + } + /// /// Returns a string with essential information for debugging. /// diff --git a/modules/swagger-codegen/src/main/resources/csharp/ApiClient.mustache b/modules/swagger-codegen/src/main/resources/csharp/ApiClient.mustache index 172e6bc627ad..707ce9eb5602 100644 --- a/modules/swagger-codegen/src/main/resources/csharp/ApiClient.mustache +++ b/modules/swagger-codegen/src/main/resources/csharp/ApiClient.mustache @@ -147,7 +147,7 @@ namespace {{packageName}}.Client } /// - /// If parameter is DateTime, output in ISO8601 format. + /// If parameter is DateTime, output in a formatted string (default ISO 8601), customizable with Configuration.DateTime. /// If parameter is a list, join the list with ",". /// Otherwise just return the string. /// @@ -156,10 +156,11 @@ namespace {{packageName}}.Client public string ParameterToString(object obj) { if (obj is DateTime) - // Return an ISO 8601 formatted string, also known as a Round-trip date/time pattern + // Return a formatted date string - Can be customized with Configuration.DateTimeFormat + // Defaults to an ISO 8601, using the known as a Round-trip date/time pattern ("o") // https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx#Anchor_8 // For example: 2009-06-15T13:45:30.0000000 - return ((DateTime)obj).ToString ("o"); + return ((DateTime)obj).ToString (Configuration.DateTimeFormat); else if (obj is IList) { string flattenString = ""; diff --git a/modules/swagger-codegen/src/main/resources/csharp/Configuration.mustache b/modules/swagger-codegen/src/main/resources/csharp/Configuration.mustache index 46dde35d8d3a..44459e54440e 100644 --- a/modules/swagger-codegen/src/main/resources/csharp/Configuration.mustache +++ b/modules/swagger-codegen/src/main/resources/csharp/Configuration.mustache @@ -138,7 +138,40 @@ namespace {{packageName}}.Client _tempFolderPath = value + Path.DirectorySeparatorChar; } } - + + private const string ISO8601_DATETIME_FORMAT = "o"; + + private static string _dateTimeFormat = ISO8601_DATETIME_FORMAT; + + /// + /// Gets or sets the the date time format used when serializing in the ApiClient + /// By default, it's set to ISO 8601 - "o", for others see: + /// https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx + /// and https://msdn.microsoft.com/en-us/library/8kb3ddd4(v=vs.110).aspx + /// No validation is done to ensure that the string you're providing is valid + /// + /// The DateTimeFormat string + public static String DateTimeFormat + { + get + { + return _dateTimeFormat; + } + set + { + if (string.IsNullOrEmpty(value)) + { + // Never allow a blank or null string, go back to the default + _dateTimeFormat = ISO8601_DATETIME_FORMAT; + return; + } + + // Caution, no validation when you choose date time format other than ISO 8601 + // Take a look at the above links + _dateTimeFormat = value; + } + } + /// /// Returns a string with essential information for debugging. /// diff --git a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Api/PetApi.cs b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Api/PetApi.cs index ba58eeac9e0e..9ab779c9f4b6 100644 --- a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Api/PetApi.cs +++ b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Api/PetApi.cs @@ -6,6 +6,7 @@ using RestSharp; using IO.Swagger.Client; using IO.Swagger.Model; + namespace IO.Swagger.Api { diff --git a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Api/StoreApi.cs b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Api/StoreApi.cs index a9e9d6e9b741..db82bf8e6440 100644 --- a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Api/StoreApi.cs +++ b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Api/StoreApi.cs @@ -6,6 +6,7 @@ using RestSharp; using IO.Swagger.Client; using IO.Swagger.Model; + namespace IO.Swagger.Api { diff --git a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Api/UserApi.cs b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Api/UserApi.cs index 5502fe15da17..ac4f138c568b 100644 --- a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Api/UserApi.cs +++ b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Api/UserApi.cs @@ -6,6 +6,7 @@ using RestSharp; using IO.Swagger.Client; using IO.Swagger.Model; + namespace IO.Swagger.Api { diff --git a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Client/ApiClient.cs b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Client/ApiClient.cs index 1dc978443a33..faf688b55853 100644 --- a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Client/ApiClient.cs +++ b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Client/ApiClient.cs @@ -147,7 +147,7 @@ namespace IO.Swagger.Client } /// - /// If parameter is DateTime, output in ISO8601 format. + /// If parameter is DateTime, output in a formatted string (default ISO 8601), customizable with Configuration.DateTime. /// If parameter is a list, join the list with ",". /// Otherwise just return the string. /// @@ -156,10 +156,11 @@ namespace IO.Swagger.Client public string ParameterToString(object obj) { if (obj is DateTime) - // Return an ISO 8601 formatted string, also known as a Round-trip date/time pattern + // Return a formatted date string - Can be customized with Configuration.DateTimeFormat + // Defaults to an ISO 8601, using the known as a Round-trip date/time pattern ("o") // https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx#Anchor_8 // For example: 2009-06-15T13:45:30.0000000 - return ((DateTime)obj).ToString ("o"); + return ((DateTime)obj).ToString (Configuration.DateTimeFormat); else if (obj is IList) { string flattenString = ""; diff --git a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Client/Configuration.cs b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Client/Configuration.cs index 151e4e422488..fcdc16f44db5 100644 --- a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Client/Configuration.cs +++ b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Client/Configuration.cs @@ -138,7 +138,40 @@ namespace IO.Swagger.Client _tempFolderPath = value + Path.DirectorySeparatorChar; } } - + + private const string ISO8601_DATETIME_FORMAT = "o"; + + private static string _dateTimeFormat = ISO8601_DATETIME_FORMAT; + + /// + /// Gets or sets the the date time format used when serializing in the ApiClient + /// By default, it's set to ISO 8601 - "o", for others see: + /// https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx + /// and https://msdn.microsoft.com/en-us/library/8kb3ddd4(v=vs.110).aspx + /// No validation is done to ensure that the string you're providing is valid + /// + /// The DateTimeFormat string + public static String DateTimeFormat + { + get + { + return _dateTimeFormat; + } + set + { + if (string.IsNullOrEmpty(value)) + { + // Never allow a blank or null string, go back to the default + _dateTimeFormat = ISO8601_DATETIME_FORMAT; + return; + } + + // Caution, no validation when you choose date time format other than ISO 8601 + // Take a look at the above links + _dateTimeFormat = value; + } + } + /// /// Returns a string with essential information for debugging. /// diff --git a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/Category.cs b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/Category.cs index d9cb6b21005d..03551f9492bc 100644 --- a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/Category.cs +++ b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/Category.cs @@ -7,6 +7,8 @@ using System.Collections.Generic; using System.Runtime.Serialization; using Newtonsoft.Json; + + namespace IO.Swagger.Model { @@ -122,4 +124,6 @@ namespace IO.Swagger.Model } } + + } diff --git a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/Order.cs b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/Order.cs index 2191707bd091..1d214430ec86 100644 --- a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/Order.cs +++ b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/Order.cs @@ -7,6 +7,8 @@ using System.Collections.Generic; using System.Runtime.Serialization; using Newtonsoft.Json; + + namespace IO.Swagger.Model { @@ -187,4 +189,6 @@ namespace IO.Swagger.Model } } + + } diff --git a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/Pet.cs b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/Pet.cs index 10c44fb46a7b..ab60577e85af 100644 --- a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/Pet.cs +++ b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/Pet.cs @@ -7,6 +7,8 @@ using System.Collections.Generic; using System.Runtime.Serialization; using Newtonsoft.Json; + + namespace IO.Swagger.Model { @@ -187,4 +189,6 @@ namespace IO.Swagger.Model } } + + } diff --git a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/Tag.cs b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/Tag.cs index 93210505bf0f..cf77c2470b2d 100644 --- a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/Tag.cs +++ b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/Tag.cs @@ -7,6 +7,8 @@ using System.Collections.Generic; using System.Runtime.Serialization; using Newtonsoft.Json; + + namespace IO.Swagger.Model { @@ -122,4 +124,6 @@ namespace IO.Swagger.Model } } + + } diff --git a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/User.cs b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/User.cs index 1fbd17da993a..eca977c3b183 100644 --- a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/User.cs +++ b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/User.cs @@ -7,6 +7,8 @@ using System.Collections.Generic; using System.Runtime.Serialization; using Newtonsoft.Json; + + namespace IO.Swagger.Model { @@ -219,4 +221,6 @@ namespace IO.Swagger.Model } } + + } diff --git a/samples/client/petstore/csharp/SwaggerClientTest/SwaggerClientTest.csproj b/samples/client/petstore/csharp/SwaggerClientTest/SwaggerClientTest.csproj index c1dc6a31e194..5556641ea1f7 100644 --- a/samples/client/petstore/csharp/SwaggerClientTest/SwaggerClientTest.csproj +++ b/samples/client/petstore/csharp/SwaggerClientTest/SwaggerClientTest.csproj @@ -1,4 +1,4 @@ - + Debug @@ -69,5 +69,9 @@ + + + + \ No newline at end of file diff --git a/samples/client/petstore/csharp/SwaggerClientTest/TestApiClient.cs b/samples/client/petstore/csharp/SwaggerClientTest/TestApiClient.cs index 5b9b27ce6569..adf59e0ae0ca 100644 --- a/samples/client/petstore/csharp/SwaggerClientTest/TestApiClient.cs +++ b/samples/client/petstore/csharp/SwaggerClientTest/TestApiClient.cs @@ -3,11 +3,18 @@ using System; using System.Collections.Generic; using IO.Swagger.Client; -namespace SwaggerClient.TestApiClient +namespace SwaggerClientTest.TestApiClient { public class TestApiClient { - [Test ()] + [TearDown()] + public void TearDown() + { + // Reset to default, just in case + Configuration.DateTimeFormat = "o"; + } + + [Test ()] public void TestParameterToString () { ApiClient api = new ApiClient (); @@ -19,20 +26,49 @@ namespace SwaggerClient.TestApiClient // test array of int List numList = new List(new int[] {1, 37}); Assert.AreEqual("1,37", api.ParameterToString (numList)); - - // test datetime - DateTime dateUtc = DateTime.Parse("2008-04-10T13:30:00.0000000z", null, System.Globalization.DateTimeStyles.RoundtripKind); - Assert.AreEqual("2008-04-10T13:30:00.0000000Z", api.ParameterToString (dateUtc)); - - // test datetime with no timezone - DateTime dateWithNoTz = DateTime.Parse("2008-04-10T13:30:00.000", null, System.Globalization.DateTimeStyles.RoundtripKind); - Assert.AreEqual("2008-04-10T13:30:00.0000000", api.ParameterToString (dateWithNoTz)); - - // test datetime with a time zone - DateTime dateWithTz = DateTime.Parse("2008-04-10T13:30:00.0000000-04:00", null, System.Globalization.DateTimeStyles.RoundtripKind); - Assert.AreEqual("2008-04-10T13:30:00.0000000-04:00", api.ParameterToString (dateWithTz)); - } - } + + [Test ()] + public void TestParameterToString_DateTime () + { + ApiClient api = new ApiClient(); + + // test datetime + DateTime dateUtc = DateTime.Parse("2008-04-10T13:30:00.0000000z", null, System.Globalization.DateTimeStyles.RoundtripKind); + Assert.AreEqual("2008-04-10T13:30:00.0000000Z", api.ParameterToString(dateUtc)); + + // test datetime with no timezone + DateTime dateWithNoTz = DateTime.Parse("2008-04-10T13:30:00.000", null, System.Globalization.DateTimeStyles.RoundtripKind); + Assert.AreEqual("2008-04-10T13:30:00.0000000", api.ParameterToString(dateWithNoTz)); + + // test datetime with a time zone + DateTime dateWithTz = DateTime.Parse("2008-04-10T13:30:00.0000000-04:00", null, System.Globalization.DateTimeStyles.RoundtripKind); + Assert.AreEqual("2008-04-10T13:30:00.0000000-04:00", api.ParameterToString(dateWithTz)); + } + + [Test ()] + public void TestParameterToString_DateTime_WithUFormat () + { + // Setup the DateTimeFormat across all of the calls + Configuration.DateTimeFormat = "u"; + ApiClient api = new ApiClient(); + + // test datetime + DateTime dateUtc = DateTime.Parse("2009-06-15 20:45:30Z", null, System.Globalization.DateTimeStyles.RoundtripKind); + Assert.AreEqual("2009-06-15 20:45:30Z", api.ParameterToString(dateUtc)); + } + + [Test ()] + public void TestParameterToString_DateTime_WithCustomFormat () + { + // Setup the DateTimeFormat across all of the calls + Configuration.DateTimeFormat = "dd/MM/yy HH:mm:ss"; + ApiClient api = new ApiClient(); + + // test datetime + DateTime dateUtc = DateTime.Parse("2009-06-15 20:45:30Z", null, System.Globalization.DateTimeStyles.RoundtripKind); + Assert.AreEqual("15/06/09 20:45:30", api.ParameterToString(dateUtc)); + } + } } diff --git a/samples/client/petstore/csharp/SwaggerClientTest/TestConfiguration.cs b/samples/client/petstore/csharp/SwaggerClientTest/TestConfiguration.cs index c508917e7d53..c72a00066918 100644 --- a/samples/client/petstore/csharp/SwaggerClientTest/TestConfiguration.cs +++ b/samples/client/petstore/csharp/SwaggerClientTest/TestConfiguration.cs @@ -5,10 +5,17 @@ using IO.Swagger.Client; using IO.Swagger.Api; using IO.Swagger.Model; -namespace SwaggerClient.TestConfiguration +namespace SwaggerClientTest.TestConfiguration { public class TestConfiguration { + [TearDown ()] + public void TearDown () + { + // Reset to default, just in case + Configuration.DateTimeFormat = "o"; + } + [Test ()] public void TestAuthentication () { @@ -32,7 +39,23 @@ namespace SwaggerClient.TestConfiguration Assert.AreNotSame (p.Configuration, Configuration.Default); } - [Test ()] + [Test ()] + public void TestDateTimeFormat_Default () + { + // Should default to the Round-trip Format Specifier - "o" + // https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx#Anchor_8 + Assert.AreEqual("o", Configuration.DateTimeFormat); + } + + [Test ()] + public void TestDateTimeFormat_UType() + { + Configuration.DateTimeFormat = "u"; + + Assert.AreEqual("u", Configuration.DateTimeFormat); + } + + [Test ()] public void TestDefautlConfiguration () { PetApi p1 = new PetApi (); diff --git a/samples/client/petstore/csharp/SwaggerClientTest/TestPet.cs b/samples/client/petstore/csharp/SwaggerClientTest/TestPet.cs index 55d081f9bb18..7c21f8efeaf1 100644 --- a/samples/client/petstore/csharp/SwaggerClientTest/TestPet.cs +++ b/samples/client/petstore/csharp/SwaggerClientTest/TestPet.cs @@ -6,9 +6,9 @@ using System.Collections.Generic; using IO.Swagger.Api; using IO.Swagger.Model; using IO.Swagger.Client; +using System.Reflection; - -namespace SwaggerClient.TestPet +namespace SwaggerClientTest.TestPet { [TestFixture ()] public class TestPet @@ -166,15 +166,15 @@ namespace SwaggerClient.TestPet [Test ()] public void TestUploadFile () { - PetApi petApi = new PetApi (); - //NOTE: please provide a valid file (full path) - FileStream fileStream = new FileStream("/var/tmp/small.gif", FileMode.Open); + Assembly _assembly = Assembly.GetExecutingAssembly(); + Stream _imageStream = _assembly.GetManifestResourceStream("SwaggerClientTest.swagger-logo.png"); + PetApi petApi = new PetApi (); // test file upload with form parameters - petApi.UploadFile(petId, "new form name", fileStream); + petApi.UploadFile(petId, "new form name", _imageStream); // test file upload without any form parameters // using optional parameter syntax introduced at .net 4.0 - petApi.UploadFile(petId: petId, file: fileStream); + petApi.UploadFile(petId: petId, file: _imageStream); } diff --git a/samples/client/petstore/csharp/SwaggerClientTest/swagger-logo.png b/samples/client/petstore/csharp/SwaggerClientTest/swagger-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..7671d64c7da5320f6a477a3ae9a6af9ebba077ae GIT binary patch literal 11917 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 Tf0=1800000NkvXXu0mjfB5M3m literal 0 HcmV?d00001 From ddc4b0a5482d382454a3e732ff3b88976d9e9075 Mon Sep 17 00:00:00 2001 From: xhh Date: Sat, 12 Dec 2015 21:33:32 +0800 Subject: [PATCH 51/71] Ruby: place properties on separate lines with description --- .../src/main/resources/ruby/model.mustache | 9 +++++---- .../ruby/lib/petstore/models/category.rb | 4 +++- .../petstore/ruby/lib/petstore/models/order.rb | 14 ++++++++++++-- .../petstore/ruby/lib/petstore/models/pet.rb | 14 ++++++++++++-- .../petstore/ruby/lib/petstore/models/tag.rb | 4 +++- .../petstore/ruby/lib/petstore/models/user.rb | 18 ++++++++++++++++-- 6 files changed, 51 insertions(+), 12 deletions(-) diff --git a/modules/swagger-codegen/src/main/resources/ruby/model.mustache b/modules/swagger-codegen/src/main/resources/ruby/model.mustache index 5d4eb954767a..f253a2c0e60f 100644 --- a/modules/swagger-codegen/src/main/resources/ruby/model.mustache +++ b/modules/swagger-codegen/src/main/resources/ruby/model.mustache @@ -1,13 +1,14 @@ module {{moduleName}}{{#models}}{{#model}}{{#description}} # {{{description}}}{{/description}} - class {{classname}} < BaseObject - attr_accessor {{#vars}}:{{{name}}}{{#hasMore}}, {{/hasMore}}{{/vars}}{{newline}} + class {{classname}} < BaseObject{{#vars}}{{#description}} + # {{{description}}}{{/description}} + attr_accessor :{{{name}}} +{{/vars}} # Attribute mapping from ruby-style variable name to JSON key. def self.attribute_map { - {{#vars}}{{#description}} - # {{{description}}}{{/description}} + {{#vars}} :'{{{name}}}' => :'{{{baseName}}}'{{#hasMore}},{{/hasMore}} {{/vars}} } diff --git a/samples/client/petstore/ruby/lib/petstore/models/category.rb b/samples/client/petstore/ruby/lib/petstore/models/category.rb index 8864ad10f753..e223e747e747 100644 --- a/samples/client/petstore/ruby/lib/petstore/models/category.rb +++ b/samples/client/petstore/ruby/lib/petstore/models/category.rb @@ -1,6 +1,8 @@ module Petstore class Category < BaseObject - attr_accessor :id, :name + attr_accessor :id + + attr_accessor :name # Attribute mapping from ruby-style variable name to JSON key. def self.attribute_map diff --git a/samples/client/petstore/ruby/lib/petstore/models/order.rb b/samples/client/petstore/ruby/lib/petstore/models/order.rb index 59c84f656660..19a33d1cfc30 100644 --- a/samples/client/petstore/ruby/lib/petstore/models/order.rb +++ b/samples/client/petstore/ruby/lib/petstore/models/order.rb @@ -1,6 +1,17 @@ module Petstore class Order < BaseObject - attr_accessor :id, :pet_id, :quantity, :ship_date, :status, :complete + attr_accessor :id + + attr_accessor :pet_id + + attr_accessor :quantity + + attr_accessor :ship_date + + # Order Status + attr_accessor :status + + attr_accessor :complete # Attribute mapping from ruby-style variable name to JSON key. def self.attribute_map @@ -14,7 +25,6 @@ module Petstore :'ship_date' => :'shipDate', - # Order Status :'status' => :'status', :'complete' => :'complete' diff --git a/samples/client/petstore/ruby/lib/petstore/models/pet.rb b/samples/client/petstore/ruby/lib/petstore/models/pet.rb index 303a12d702cd..fb967cbbab4f 100644 --- a/samples/client/petstore/ruby/lib/petstore/models/pet.rb +++ b/samples/client/petstore/ruby/lib/petstore/models/pet.rb @@ -1,6 +1,17 @@ module Petstore class Pet < BaseObject - attr_accessor :id, :category, :name, :photo_urls, :tags, :status + attr_accessor :id + + attr_accessor :category + + attr_accessor :name + + attr_accessor :photo_urls + + attr_accessor :tags + + # pet status in the store + attr_accessor :status # Attribute mapping from ruby-style variable name to JSON key. def self.attribute_map @@ -16,7 +27,6 @@ module Petstore :'tags' => :'tags', - # pet status in the store :'status' => :'status' } diff --git a/samples/client/petstore/ruby/lib/petstore/models/tag.rb b/samples/client/petstore/ruby/lib/petstore/models/tag.rb index 06d779c2c547..681c2a2a5c94 100644 --- a/samples/client/petstore/ruby/lib/petstore/models/tag.rb +++ b/samples/client/petstore/ruby/lib/petstore/models/tag.rb @@ -1,6 +1,8 @@ module Petstore class Tag < BaseObject - attr_accessor :id, :name + attr_accessor :id + + attr_accessor :name # Attribute mapping from ruby-style variable name to JSON key. def self.attribute_map diff --git a/samples/client/petstore/ruby/lib/petstore/models/user.rb b/samples/client/petstore/ruby/lib/petstore/models/user.rb index 1b49db1c96be..ca00bf34be13 100644 --- a/samples/client/petstore/ruby/lib/petstore/models/user.rb +++ b/samples/client/petstore/ruby/lib/petstore/models/user.rb @@ -1,6 +1,21 @@ module Petstore class User < BaseObject - attr_accessor :id, :username, :first_name, :last_name, :email, :password, :phone, :user_status + attr_accessor :id + + attr_accessor :username + + attr_accessor :first_name + + attr_accessor :last_name + + attr_accessor :email + + attr_accessor :password + + attr_accessor :phone + + # User Status + attr_accessor :user_status # Attribute mapping from ruby-style variable name to JSON key. def self.attribute_map @@ -20,7 +35,6 @@ module Petstore :'phone' => :'phone', - # User Status :'user_status' => :'userStatus' } From bef2dac0229d98057795910ccf30cb3a98d36ae5 Mon Sep 17 00:00:00 2001 From: wing328 Date: Sun, 13 Dec 2015 17:22:30 +0800 Subject: [PATCH 52/71] fix add route in sinatra --- .../src/main/resources/sinatra/Swaggering.rb | 6 ++++-- .../src/main/resources/sinatra/api.mustache | 2 +- .../src/main/resources/sinatra/my_app.mustache | 7 ++++--- samples/server/petstore/sinatra/api/pet_api.rb | 16 ++++++++-------- .../server/petstore/sinatra/api/store_api.rb | 8 ++++---- .../server/petstore/sinatra/api/user_api.rb | 18 +++++++++--------- .../server/petstore/sinatra/lib/swaggering.rb | 6 ++++-- samples/server/petstore/sinatra/my_app.rb | 4 ++++ 8 files changed, 38 insertions(+), 29 deletions(-) diff --git a/modules/swagger-codegen/src/main/resources/sinatra/Swaggering.rb b/modules/swagger-codegen/src/main/resources/sinatra/Swaggering.rb index 79aca1da2c92..14882a924d77 100644 --- a/modules/swagger-codegen/src/main/resources/sinatra/Swaggering.rb +++ b/modules/swagger-codegen/src/main/resources/sinatra/Swaggering.rb @@ -31,9 +31,10 @@ class Swaggering < Sinatra::Base end def self.add_route(method, path, swag={}, opts={}, &block) - fullPath = swag["resourcePath"].to_s + @@configuration.format_specifier + path + #fullPath = swag["resourcePath"].to_s + @@configuration.format_specifier + path + fullPath = path.gsub(/{(.*)}/, ':\1') - accepted = case method + accepted = case method.to_s.downcase when 'get' get(fullPath, opts, &block) true @@ -47,6 +48,7 @@ class Swaggering < Sinatra::Base put(fullPath, opts, &block) true else + puts "Error adding route: #{method} #{fullPath}" false end diff --git a/modules/swagger-codegen/src/main/resources/sinatra/api.mustache b/modules/swagger-codegen/src/main/resources/sinatra/api.mustache index 7dffb94cdf0b..27830feed31e 100644 --- a/modules/swagger-codegen/src/main/resources/sinatra/api.mustache +++ b/modules/swagger-codegen/src/main/resources/sinatra/api.mustache @@ -3,7 +3,7 @@ require 'json' {{#operations}} {{#operation}} -MyApp.add_route('{{httpMethod}}', '{{path}}', { +MyApp.add_route('{{httpMethod}}', '{{basePathWithoutHost}}{{path}}', { "resourcePath" => "/{{baseName}}", "summary" => "{{{summary}}}", "nickname" => "{{nickname}}", diff --git a/modules/swagger-codegen/src/main/resources/sinatra/my_app.mustache b/modules/swagger-codegen/src/main/resources/sinatra/my_app.mustache index 8c4a16d7ff50..7d4e87adffc1 100644 --- a/modules/swagger-codegen/src/main/resources/sinatra/my_app.mustache +++ b/modules/swagger-codegen/src/main/resources/sinatra/my_app.mustache @@ -7,6 +7,7 @@ class MyApp < Swaggering end end -{{#apis}} -require './lib/{{className}}.rb' -{{/apis}} +# include the api files +Dir["./api/*.rb"].each { |file| + require file +} diff --git a/samples/server/petstore/sinatra/api/pet_api.rb b/samples/server/petstore/sinatra/api/pet_api.rb index 5f995c531d85..7ccad2056b92 100644 --- a/samples/server/petstore/sinatra/api/pet_api.rb +++ b/samples/server/petstore/sinatra/api/pet_api.rb @@ -1,7 +1,7 @@ require 'json' -MyApp.add_route('PUT', '/pet', { +MyApp.add_route('PUT', '/v2/pet', { "resourcePath" => "/Pet", "summary" => "Update an existing pet", "nickname" => "update_pet", @@ -28,7 +28,7 @@ MyApp.add_route('PUT', '/pet', { end -MyApp.add_route('POST', '/pet', { +MyApp.add_route('POST', '/v2/pet', { "resourcePath" => "/Pet", "summary" => "Add a new pet to the store", "nickname" => "add_pet", @@ -55,7 +55,7 @@ MyApp.add_route('POST', '/pet', { end -MyApp.add_route('GET', '/pet/findByStatus', { +MyApp.add_route('GET', '/v2/pet/findByStatus', { "resourcePath" => "/Pet", "summary" => "Finds Pets by status", "nickname" => "find_pets_by_status", @@ -85,7 +85,7 @@ MyApp.add_route('GET', '/pet/findByStatus', { end -MyApp.add_route('GET', '/pet/findByTags', { +MyApp.add_route('GET', '/v2/pet/findByTags', { "resourcePath" => "/Pet", "summary" => "Finds Pets by tags", "nickname" => "find_pets_by_tags", @@ -115,7 +115,7 @@ MyApp.add_route('GET', '/pet/findByTags', { end -MyApp.add_route('GET', '/pet/{petId}', { +MyApp.add_route('GET', '/v2/pet/{petId}', { "resourcePath" => "/Pet", "summary" => "Find pet by ID", "nickname" => "get_pet_by_id", @@ -142,7 +142,7 @@ MyApp.add_route('GET', '/pet/{petId}', { end -MyApp.add_route('POST', '/pet/{petId}', { +MyApp.add_route('POST', '/v2/pet/{petId}', { "resourcePath" => "/Pet", "summary" => "Updates a pet in the store with form data", "nickname" => "update_pet_with_form", @@ -169,7 +169,7 @@ MyApp.add_route('POST', '/pet/{petId}', { end -MyApp.add_route('DELETE', '/pet/{petId}', { +MyApp.add_route('DELETE', '/v2/pet/{petId}', { "resourcePath" => "/Pet", "summary" => "Deletes a pet", "nickname" => "delete_pet", @@ -203,7 +203,7 @@ MyApp.add_route('DELETE', '/pet/{petId}', { end -MyApp.add_route('POST', '/pet/{petId}/uploadImage', { +MyApp.add_route('POST', '/v2/pet/{petId}/uploadImage', { "resourcePath" => "/Pet", "summary" => "uploads an image", "nickname" => "upload_file", diff --git a/samples/server/petstore/sinatra/api/store_api.rb b/samples/server/petstore/sinatra/api/store_api.rb index 244983874127..37938b304db1 100644 --- a/samples/server/petstore/sinatra/api/store_api.rb +++ b/samples/server/petstore/sinatra/api/store_api.rb @@ -1,7 +1,7 @@ require 'json' -MyApp.add_route('GET', '/store/inventory', { +MyApp.add_route('GET', '/v2/store/inventory', { "resourcePath" => "/Store", "summary" => "Returns pet inventories by status", "nickname" => "get_inventory", @@ -21,7 +21,7 @@ MyApp.add_route('GET', '/store/inventory', { end -MyApp.add_route('POST', '/store/order', { +MyApp.add_route('POST', '/v2/store/order', { "resourcePath" => "/Store", "summary" => "Place an order for a pet", "nickname" => "place_order", @@ -48,7 +48,7 @@ MyApp.add_route('POST', '/store/order', { end -MyApp.add_route('GET', '/store/order/{orderId}', { +MyApp.add_route('GET', '/v2/store/order/{orderId}', { "resourcePath" => "/Store", "summary" => "Find purchase order by ID", "nickname" => "get_order_by_id", @@ -75,7 +75,7 @@ MyApp.add_route('GET', '/store/order/{orderId}', { end -MyApp.add_route('DELETE', '/store/order/{orderId}', { +MyApp.add_route('DELETE', '/v2/store/order/{orderId}', { "resourcePath" => "/Store", "summary" => "Delete purchase order by ID", "nickname" => "delete_order", diff --git a/samples/server/petstore/sinatra/api/user_api.rb b/samples/server/petstore/sinatra/api/user_api.rb index 98f50549ba11..7b890004891d 100644 --- a/samples/server/petstore/sinatra/api/user_api.rb +++ b/samples/server/petstore/sinatra/api/user_api.rb @@ -1,7 +1,7 @@ require 'json' -MyApp.add_route('POST', '/user', { +MyApp.add_route('POST', '/v2/user', { "resourcePath" => "/User", "summary" => "Create user", "nickname" => "create_user", @@ -28,7 +28,7 @@ MyApp.add_route('POST', '/user', { end -MyApp.add_route('POST', '/user/createWithArray', { +MyApp.add_route('POST', '/v2/user/createWithArray', { "resourcePath" => "/User", "summary" => "Creates list of users with given input array", "nickname" => "create_users_with_array_input", @@ -55,7 +55,7 @@ MyApp.add_route('POST', '/user/createWithArray', { end -MyApp.add_route('POST', '/user/createWithList', { +MyApp.add_route('POST', '/v2/user/createWithList', { "resourcePath" => "/User", "summary" => "Creates list of users with given input array", "nickname" => "create_users_with_list_input", @@ -82,7 +82,7 @@ MyApp.add_route('POST', '/user/createWithList', { end -MyApp.add_route('GET', '/user/login', { +MyApp.add_route('GET', '/v2/user/login', { "resourcePath" => "/User", "summary" => "Logs user into the system", "nickname" => "login_user", @@ -122,7 +122,7 @@ MyApp.add_route('GET', '/user/login', { end -MyApp.add_route('GET', '/user/logout', { +MyApp.add_route('GET', '/v2/user/logout', { "resourcePath" => "/User", "summary" => "Logs out current logged in user session", "nickname" => "logout_user", @@ -142,7 +142,7 @@ MyApp.add_route('GET', '/user/logout', { end -MyApp.add_route('GET', '/user/{username}', { +MyApp.add_route('GET', '/v2/user/{username}', { "resourcePath" => "/User", "summary" => "Get user by user name", "nickname" => "get_user_by_name", @@ -154,7 +154,7 @@ MyApp.add_route('GET', '/user/{username}', { { "name" => "username", - "description" => "The name that needs to be fetched. Use user1 for testing. ", + "description" => "The name that needs to be fetched. Use user1 for testing.", "dataType" => "string", "paramType" => "path", }, @@ -169,7 +169,7 @@ MyApp.add_route('GET', '/user/{username}', { end -MyApp.add_route('PUT', '/user/{username}', { +MyApp.add_route('PUT', '/v2/user/{username}', { "resourcePath" => "/User", "summary" => "Updated user", "nickname" => "update_user", @@ -203,7 +203,7 @@ MyApp.add_route('PUT', '/user/{username}', { end -MyApp.add_route('DELETE', '/user/{username}', { +MyApp.add_route('DELETE', '/v2/user/{username}', { "resourcePath" => "/User", "summary" => "Delete user", "nickname" => "delete_user", diff --git a/samples/server/petstore/sinatra/lib/swaggering.rb b/samples/server/petstore/sinatra/lib/swaggering.rb index 79aca1da2c92..14882a924d77 100644 --- a/samples/server/petstore/sinatra/lib/swaggering.rb +++ b/samples/server/petstore/sinatra/lib/swaggering.rb @@ -31,9 +31,10 @@ class Swaggering < Sinatra::Base end def self.add_route(method, path, swag={}, opts={}, &block) - fullPath = swag["resourcePath"].to_s + @@configuration.format_specifier + path + #fullPath = swag["resourcePath"].to_s + @@configuration.format_specifier + path + fullPath = path.gsub(/{(.*)}/, ':\1') - accepted = case method + accepted = case method.to_s.downcase when 'get' get(fullPath, opts, &block) true @@ -47,6 +48,7 @@ class Swaggering < Sinatra::Base put(fullPath, opts, &block) true else + puts "Error adding route: #{method} #{fullPath}" false end diff --git a/samples/server/petstore/sinatra/my_app.rb b/samples/server/petstore/sinatra/my_app.rb index 9f4d991d0f1d..33376ef311d9 100644 --- a/samples/server/petstore/sinatra/my_app.rb +++ b/samples/server/petstore/sinatra/my_app.rb @@ -7,3 +7,7 @@ class MyApp < Swaggering end end +# include the api files +Dir["./api/*.rb"].each { |file| + require file +} From 1dd05bb90fb0b459867c044bf103d66c8367ec95 Mon Sep 17 00:00:00 2001 From: wing328 Date: Sun, 13 Dec 2015 17:39:52 +0800 Subject: [PATCH 53/71] add swagger.yaml to ruby sinatra --- .../languages/SinatraServerCodegen.java | 18 + .../src/main/resources/sinatra/Swaggering.rb | 7 + .../main/resources/sinatra/swagger.mustache | 1 + .../server/petstore/sinatra/lib/swaggering.rb | 7 + samples/server/petstore/sinatra/swagger.yaml | 667 ++++++++++++++++++ 5 files changed, 700 insertions(+) create mode 100644 modules/swagger-codegen/src/main/resources/sinatra/swagger.mustache create mode 100644 samples/server/petstore/sinatra/swagger.yaml diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/SinatraServerCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/SinatraServerCodegen.java index 9bcece874299..1c31b45664e6 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/SinatraServerCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/SinatraServerCodegen.java @@ -1,5 +1,7 @@ package io.swagger.codegen.languages; +import com.fasterxml.jackson.core.JsonProcessingException; + import io.swagger.codegen.CliOption; import io.swagger.codegen.CodegenConfig; import io.swagger.codegen.CodegenType; @@ -8,10 +10,13 @@ import io.swagger.codegen.SupportingFile; import io.swagger.models.properties.ArrayProperty; import io.swagger.models.properties.MapProperty; import io.swagger.models.properties.Property; +import io.swagger.models.Swagger; +import io.swagger.util.Yaml; import java.io.File; import java.util.Arrays; import java.util.HashSet; +import java.util.Map; import org.apache.commons.lang.StringUtils; @@ -73,6 +78,7 @@ public class SinatraServerCodegen extends DefaultCodegen implements CodegenConfi supportingFiles.add(new SupportingFile("config.ru", "", "config.ru")); supportingFiles.add(new SupportingFile("Gemfile", "", "Gemfile")); supportingFiles.add(new SupportingFile("README.md", "", "README.md")); + supportingFiles.add(new SupportingFile("swagger.mustache","","swagger.yaml")); } public CodegenType getTag() { @@ -213,5 +219,17 @@ public class SinatraServerCodegen extends DefaultCodegen implements CodegenConfi return underscore(operationId); } + @Override + public Map postProcessSupportingFileData(Map objs) { + Swagger swagger = (Swagger)objs.get("swagger"); + if(swagger != null) { + try { + objs.put("swagger-yaml", Yaml.mapper().writeValueAsString(swagger)); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + } + return super.postProcessSupportingFileData(objs); + } } diff --git a/modules/swagger-codegen/src/main/resources/sinatra/Swaggering.rb b/modules/swagger-codegen/src/main/resources/sinatra/Swaggering.rb index 14882a924d77..1357bb19134b 100644 --- a/modules/swagger-codegen/src/main/resources/sinatra/Swaggering.rb +++ b/modules/swagger-codegen/src/main/resources/sinatra/Swaggering.rb @@ -26,6 +26,13 @@ class Swaggering < Sinatra::Base cross_origin Swaggering.to_resource_listing } + + # for swagger.yaml + get("/swagger.yaml") { + cross_origin + File.read("./swagger.yaml"); + } + @@configuration ||= Configuration.new yield(@@configuration) if block_given? end diff --git a/modules/swagger-codegen/src/main/resources/sinatra/swagger.mustache b/modules/swagger-codegen/src/main/resources/sinatra/swagger.mustache new file mode 100644 index 000000000000..51560926bba1 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/sinatra/swagger.mustache @@ -0,0 +1 @@ +{{{swagger-yaml}}} \ No newline at end of file diff --git a/samples/server/petstore/sinatra/lib/swaggering.rb b/samples/server/petstore/sinatra/lib/swaggering.rb index 14882a924d77..1357bb19134b 100644 --- a/samples/server/petstore/sinatra/lib/swaggering.rb +++ b/samples/server/petstore/sinatra/lib/swaggering.rb @@ -26,6 +26,13 @@ class Swaggering < Sinatra::Base cross_origin Swaggering.to_resource_listing } + + # for swagger.yaml + get("/swagger.yaml") { + cross_origin + File.read("./swagger.yaml"); + } + @@configuration ||= Configuration.new yield(@@configuration) if block_given? end diff --git a/samples/server/petstore/sinatra/swagger.yaml b/samples/server/petstore/sinatra/swagger.yaml new file mode 100644 index 000000000000..49a3405de09a --- /dev/null +++ b/samples/server/petstore/sinatra/swagger.yaml @@ -0,0 +1,667 @@ +--- +swagger: "2.0" +info: + description: "This is a sample server Petstore server. You can find out more about\ + \ Swagger at http://swagger.io or on irc.freenode.net,\ + \ #swagger. For this sample, you can use the api key \"special-key\" to test\ + \ the authorization filters" + version: "1.0.0" + title: "Swagger Petstore" + termsOfService: "http://swagger.io/terms/" + contact: + email: "apiteam@swagger.io" + license: + name: "Apache 2.0" + url: "http://www.apache.org/licenses/LICENSE-2.0.html" +host: "petstore.swagger.io" +basePath: "/v2" +schemes: +- "http" +paths: + /pet: + post: + tags: + - "pet" + summary: "Add a new pet to the store" + description: "" + operationId: "addPet" + consumes: + - "application/json" + - "application/xml" + produces: + - "application/json" + - "application/xml" + parameters: + - in: "body" + name: "body" + description: "Pet object that needs to be added to the store" + required: false + schema: + $ref: "#/definitions/Pet" + responses: + 405: + description: "Invalid input" + security: + - petstore_auth: + - "write:pets" + - "read:pets" + put: + tags: + - "pet" + summary: "Update an existing pet" + description: "" + operationId: "updatePet" + consumes: + - "application/json" + - "application/xml" + produces: + - "application/json" + - "application/xml" + parameters: + - in: "body" + name: "body" + description: "Pet object that needs to be added to the store" + required: false + schema: + $ref: "#/definitions/Pet" + responses: + 400: + description: "Invalid ID supplied" + 404: + description: "Pet not found" + 405: + description: "Validation exception" + security: + - petstore_auth: + - "write:pets" + - "read:pets" + /pet/findByStatus: + get: + tags: + - "pet" + summary: "Finds Pets by status" + description: "Multiple status values can be provided with comma seperated strings" + operationId: "findPetsByStatus" + produces: + - "application/json" + - "application/xml" + parameters: + - name: "status" + in: "query" + description: "Status values that need to be considered for filter" + required: false + type: "array" + items: + type: "string" + collectionFormat: "multi" + default: "available" + responses: + 200: + description: "successful operation" + schema: + type: "array" + items: + $ref: "#/definitions/Pet" + 400: + description: "Invalid status value" + security: + - petstore_auth: + - "write:pets" + - "read:pets" + /pet/findByTags: + get: + tags: + - "pet" + summary: "Finds Pets by tags" + description: "Muliple tags can be provided with comma seperated strings. Use\ + \ tag1, tag2, tag3 for testing." + operationId: "findPetsByTags" + produces: + - "application/json" + - "application/xml" + parameters: + - name: "tags" + in: "query" + description: "Tags to filter by" + required: false + type: "array" + items: + type: "string" + collectionFormat: "multi" + responses: + 200: + description: "successful operation" + schema: + type: "array" + items: + $ref: "#/definitions/Pet" + 400: + description: "Invalid tag value" + security: + - petstore_auth: + - "write:pets" + - "read:pets" + /pet/{petId}: + get: + tags: + - "pet" + summary: "Find pet by ID" + description: "Returns a pet when ID < 10. ID > 10 or nonintegers will simulate\ + \ API error conditions" + operationId: "getPetById" + produces: + - "application/json" + - "application/xml" + parameters: + - name: "petId" + in: "path" + description: "ID of pet that needs to be fetched" + required: true + type: "integer" + format: "int64" + responses: + 200: + description: "successful operation" + schema: + $ref: "#/definitions/Pet" + 400: + description: "Invalid ID supplied" + 404: + description: "Pet not found" + security: + - api_key: [] + - petstore_auth: + - "write:pets" + - "read:pets" + post: + tags: + - "pet" + summary: "Updates a pet in the store with form data" + description: "" + operationId: "updatePetWithForm" + consumes: + - "application/x-www-form-urlencoded" + produces: + - "application/json" + - "application/xml" + parameters: + - name: "petId" + in: "path" + description: "ID of pet that needs to be updated" + required: true + type: "string" + - name: "name" + in: "formData" + description: "Updated name of the pet" + required: false + type: "string" + - name: "status" + in: "formData" + description: "Updated status of the pet" + required: false + type: "string" + responses: + 405: + description: "Invalid input" + security: + - petstore_auth: + - "write:pets" + - "read:pets" + delete: + tags: + - "pet" + summary: "Deletes a pet" + description: "" + operationId: "deletePet" + produces: + - "application/json" + - "application/xml" + parameters: + - name: "api_key" + in: "header" + description: "" + required: false + type: "string" + - name: "petId" + in: "path" + description: "Pet id to delete" + required: true + type: "integer" + format: "int64" + responses: + 400: + description: "Invalid pet value" + security: + - petstore_auth: + - "write:pets" + - "read:pets" + /pet/{petId}/uploadImage: + post: + tags: + - "pet" + summary: "uploads an image" + description: "" + operationId: "uploadFile" + consumes: + - "multipart/form-data" + produces: + - "application/json" + - "application/xml" + parameters: + - name: "petId" + in: "path" + description: "ID of pet to update" + required: true + type: "integer" + format: "int64" + - name: "additionalMetadata" + in: "formData" + description: "Additional data to pass to server" + required: false + type: "string" + - name: "file" + in: "formData" + description: "file to upload" + required: false + type: "file" + responses: + default: + description: "successful operation" + security: + - petstore_auth: + - "write:pets" + - "read:pets" + /store/inventory: + get: + tags: + - "store" + summary: "Returns pet inventories by status" + description: "Returns a map of status codes to quantities" + operationId: "getInventory" + produces: + - "application/json" + - "application/xml" + parameters: [] + responses: + 200: + description: "successful operation" + schema: + type: "object" + additionalProperties: + type: "integer" + format: "int32" + security: + - api_key: [] + /store/order: + post: + tags: + - "store" + summary: "Place an order for a pet" + description: "" + operationId: "placeOrder" + produces: + - "application/json" + - "application/xml" + parameters: + - in: "body" + name: "body" + description: "order placed for purchasing the pet" + required: false + schema: + $ref: "#/definitions/Order" + responses: + 200: + description: "successful operation" + schema: + $ref: "#/definitions/Order" + 400: + description: "Invalid Order" + /store/order/{orderId}: + get: + tags: + - "store" + summary: "Find purchase order by ID" + description: "For valid response try integer IDs with value <= 5 or > 10. Other\ + \ values will generated exceptions" + operationId: "getOrderById" + produces: + - "application/json" + - "application/xml" + parameters: + - name: "orderId" + in: "path" + description: "ID of pet that needs to be fetched" + required: true + type: "string" + responses: + 200: + description: "successful operation" + schema: + $ref: "#/definitions/Order" + 400: + description: "Invalid ID supplied" + 404: + description: "Order not found" + delete: + tags: + - "store" + summary: "Delete purchase order by ID" + description: "For valid response try integer IDs with value < 1000. Anything\ + \ above 1000 or nonintegers will generate API errors" + operationId: "deleteOrder" + produces: + - "application/json" + - "application/xml" + parameters: + - name: "orderId" + in: "path" + description: "ID of the order that needs to be deleted" + required: true + type: "string" + responses: + 400: + description: "Invalid ID supplied" + 404: + description: "Order not found" + /user: + post: + tags: + - "user" + summary: "Create user" + description: "This can only be done by the logged in user." + operationId: "createUser" + produces: + - "application/json" + - "application/xml" + parameters: + - in: "body" + name: "body" + description: "Created user object" + required: false + schema: + $ref: "#/definitions/User" + responses: + default: + description: "successful operation" + /user/createWithArray: + post: + tags: + - "user" + summary: "Creates list of users with given input array" + description: "" + operationId: "createUsersWithArrayInput" + produces: + - "application/json" + - "application/xml" + parameters: + - in: "body" + name: "body" + description: "List of user object" + required: false + schema: + type: "array" + items: + $ref: "#/definitions/User" + responses: + default: + description: "successful operation" + /user/createWithList: + post: + tags: + - "user" + summary: "Creates list of users with given input array" + description: "" + operationId: "createUsersWithListInput" + produces: + - "application/json" + - "application/xml" + parameters: + - in: "body" + name: "body" + description: "List of user object" + required: false + schema: + type: "array" + items: + $ref: "#/definitions/User" + responses: + default: + description: "successful operation" + /user/login: + get: + tags: + - "user" + summary: "Logs user into the system" + description: "" + operationId: "loginUser" + produces: + - "application/json" + - "application/xml" + parameters: + - name: "username" + in: "query" + description: "The user name for login" + required: false + type: "string" + - name: "password" + in: "query" + description: "The password for login in clear text" + required: false + type: "string" + responses: + 200: + description: "successful operation" + schema: + type: "string" + 400: + description: "Invalid username/password supplied" + /user/logout: + get: + tags: + - "user" + summary: "Logs out current logged in user session" + description: "" + operationId: "logoutUser" + produces: + - "application/json" + - "application/xml" + parameters: [] + responses: + default: + description: "successful operation" + /user/{username}: + get: + tags: + - "user" + summary: "Get user by user name" + description: "" + operationId: "getUserByName" + produces: + - "application/json" + - "application/xml" + parameters: + - name: "username" + in: "path" + description: "The name that needs to be fetched. Use user1 for testing. " + required: true + type: "string" + responses: + 200: + description: "successful operation" + schema: + $ref: "#/definitions/User" + examples: + application/json: + id: 1 + username: "johnp" + firstName: "John" + lastName: "Public" + email: "johnp@swagger.io" + password: "-secret-" + phone: "0123456789" + userStatus: 0 + 400: + description: "Invalid username supplied" + 404: + description: "User not found" + put: + tags: + - "user" + summary: "Updated user" + description: "This can only be done by the logged in user." + operationId: "updateUser" + produces: + - "application/json" + - "application/xml" + parameters: + - name: "username" + in: "path" + description: "name that need to be deleted" + required: true + type: "string" + - in: "body" + name: "body" + description: "Updated user object" + required: false + schema: + $ref: "#/definitions/User" + responses: + 400: + description: "Invalid user supplied" + 404: + description: "User not found" + delete: + tags: + - "user" + summary: "Delete user" + description: "This can only be done by the logged in user." + operationId: "deleteUser" + produces: + - "application/json" + - "application/xml" + parameters: + - name: "username" + in: "path" + description: "The name that needs to be deleted" + required: true + type: "string" + responses: + 400: + description: "Invalid username supplied" + 404: + description: "User not found" +securityDefinitions: + api_key: + type: "apiKey" + name: "api_key" + in: "header" + petstore_auth: + type: "oauth2" + authorizationUrl: "http://petstore.swagger.io/api/oauth/dialog" + flow: "implicit" + scopes: + write:pets: "modify pets in your account" + read:pets: "read your pets" +definitions: + User: + properties: + id: + type: "integer" + format: "int64" + username: + type: "string" + firstName: + type: "string" + lastName: + type: "string" + email: + type: "string" + password: + type: "string" + phone: + type: "string" + userStatus: + type: "integer" + format: "int32" + description: "User Status" + xml: + name: "User" + Category: + properties: + id: + type: "integer" + format: "int64" + name: + type: "string" + xml: + name: "Category" + Pet: + required: + - "name" + - "photoUrls" + properties: + id: + type: "integer" + format: "int64" + category: + $ref: "#/definitions/Category" + name: + type: "string" + example: "doggie" + photoUrls: + type: "array" + xml: + name: "photoUrl" + wrapped: true + items: + type: "string" + tags: + type: "array" + xml: + name: "tag" + wrapped: true + items: + $ref: "#/definitions/Tag" + status: + type: "string" + description: "pet status in the store" + enum: + - "available" + - "pending" + - "sold" + xml: + name: "Pet" + Tag: + properties: + id: + type: "integer" + format: "int64" + name: + type: "string" + xml: + name: "Tag" + Order: + properties: + id: + type: "integer" + format: "int64" + petId: + type: "integer" + format: "int64" + quantity: + type: "integer" + format: "int32" + shipDate: + type: "string" + format: "date-time" + status: + type: "string" + description: "Order Status" + enum: + - "placed" + - "approved" + - "delivered" + complete: + type: "boolean" + xml: + name: "Order" From 909ec298af11515dd959c1c8afc0bc6b9d978b52 Mon Sep 17 00:00:00 2001 From: wing328 Date: Sun, 13 Dec 2015 18:18:49 +0800 Subject: [PATCH 54/71] update regex to non-greedy match --- .../swagger-codegen/src/main/resources/sinatra/Swaggering.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/swagger-codegen/src/main/resources/sinatra/Swaggering.rb b/modules/swagger-codegen/src/main/resources/sinatra/Swaggering.rb index 1357bb19134b..69cc74556ac6 100644 --- a/modules/swagger-codegen/src/main/resources/sinatra/Swaggering.rb +++ b/modules/swagger-codegen/src/main/resources/sinatra/Swaggering.rb @@ -39,7 +39,7 @@ class Swaggering < Sinatra::Base def self.add_route(method, path, swag={}, opts={}, &block) #fullPath = swag["resourcePath"].to_s + @@configuration.format_specifier + path - fullPath = path.gsub(/{(.*)}/, ':\1') + fullPath = path.gsub(/{(.*?)}/, ':\1') accepted = case method.to_s.downcase when 'get' From f03bc1f3bc753132e6f2ce4d4e52ff2575ab1584 Mon Sep 17 00:00:00 2001 From: wing328 Date: Mon, 14 Dec 2015 16:07:41 +0800 Subject: [PATCH 55/71] remove some static methods in configuration --- .../main/resources/csharp/ApiClient.mustache | 39 ++++++++++++++++-- .../resources/csharp/Configuration.mustache | 8 ++-- .../src/main/csharp/IO/Swagger/Api/PetApi.cs | 1 - .../main/csharp/IO/Swagger/Api/StoreApi.cs | 1 - .../src/main/csharp/IO/Swagger/Api/UserApi.cs | 1 - .../csharp/IO/Swagger/Client/ApiClient.cs | 39 ++++++++++++++++-- .../csharp/IO/Swagger/Client/Configuration.cs | 8 ++-- .../main/csharp/IO/Swagger/Model/Category.cs | 4 -- .../src/main/csharp/IO/Swagger/Model/Order.cs | 4 -- .../src/main/csharp/IO/Swagger/Model/Pet.cs | 4 -- .../src/main/csharp/IO/Swagger/Model/Tag.cs | 4 -- .../src/main/csharp/IO/Swagger/Model/User.cs | 4 -- .../csharp/SwaggerClientTest/TestApiClient.cs | 34 ++++++++------- .../SwaggerClientTest/TestConfiguration.cs | 8 ++-- .../bin/Debug/SwaggerClientTest.dll | Bin 98816 -> 113152 bytes .../bin/Debug/SwaggerClientTest.dll.mdb | Bin 29758 -> 30575 bytes ...ClientTest.csproj.FilesWrittenAbsolute.txt | 1 + .../obj/Debug/SwaggerClientTest.dll | Bin 98816 -> 113152 bytes .../obj/Debug/SwaggerClientTest.dll.mdb | Bin 29758 -> 30575 bytes 19 files changed, 105 insertions(+), 55 deletions(-) diff --git a/modules/swagger-codegen/src/main/resources/csharp/ApiClient.mustache b/modules/swagger-codegen/src/main/resources/csharp/ApiClient.mustache index 707ce9eb5602..b8b9fc7a5a18 100644 --- a/modules/swagger-codegen/src/main/resources/csharp/ApiClient.mustache +++ b/modules/swagger-codegen/src/main/resources/csharp/ApiClient.mustache @@ -19,23 +19,56 @@ namespace {{packageName}}.Client public class ApiClient { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class + /// with default configuration and base path ({{basePath}}). + /// + public ApiClient() + { + Configuration = Configuration.Default; + RestClient = new RestClient("{{basePath}}"); + } + + /// + /// Initializes a new instance of the class + /// with default base path ({{basePath}}). + /// + /// An instance of Configuration. + public ApiClient(Configuration config = null) + { + if (config == null) + Configuration = Configuration.Default; + else + Configuration = config; + + RestClient = new RestClient("{{basePath}}"); + } + + /// + /// Initializes a new instance of the class + /// with default configuration. /// /// The base path. - public ApiClient(String basePath="{{basePath}}") + public ApiClient(String basePath = "{{basePath}}") { if (String.IsNullOrEmpty(basePath)) throw new ArgumentException("basePath cannot be empty"); RestClient = new RestClient(basePath); + Configuration = Configuration.Default; } /// /// Gets or sets the default API client for making HTTP calls. /// /// The default API client. - public static ApiClient Default = new ApiClient(); + public static ApiClient Default = new ApiClient(Configuration.Default); + /// + /// Gets or sets the Configuration. + /// + /// An instance of the Configuration. + public Configuration Configuration { get; set; } + /// /// Gets or sets the RestClient. /// diff --git a/modules/swagger-codegen/src/main/resources/csharp/Configuration.mustache b/modules/swagger-codegen/src/main/resources/csharp/Configuration.mustache index 44459e54440e..440288a48327 100644 --- a/modules/swagger-codegen/src/main/resources/csharp/Configuration.mustache +++ b/modules/swagger-codegen/src/main/resources/csharp/Configuration.mustache @@ -109,13 +109,13 @@ namespace {{packageName}}.Client return apiKeyValue; } - private static string _tempFolderPath = Path.GetTempPath(); + private string _tempFolderPath = Path.GetTempPath(); /// /// Gets or sets the temporary folder path to store the files downloaded from the server. /// /// Folder path. - public static String TempFolderPath + public String TempFolderPath { get { return _tempFolderPath; } @@ -141,7 +141,7 @@ namespace {{packageName}}.Client private const string ISO8601_DATETIME_FORMAT = "o"; - private static string _dateTimeFormat = ISO8601_DATETIME_FORMAT; + private string _dateTimeFormat = ISO8601_DATETIME_FORMAT; /// /// Gets or sets the the date time format used when serializing in the ApiClient @@ -151,7 +151,7 @@ namespace {{packageName}}.Client /// No validation is done to ensure that the string you're providing is valid /// /// The DateTimeFormat string - public static String DateTimeFormat + public String DateTimeFormat { get { diff --git a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Api/PetApi.cs b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Api/PetApi.cs index 9ab779c9f4b6..ba58eeac9e0e 100644 --- a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Api/PetApi.cs +++ b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Api/PetApi.cs @@ -6,7 +6,6 @@ using RestSharp; using IO.Swagger.Client; using IO.Swagger.Model; - namespace IO.Swagger.Api { diff --git a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Api/StoreApi.cs b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Api/StoreApi.cs index db82bf8e6440..a9e9d6e9b741 100644 --- a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Api/StoreApi.cs +++ b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Api/StoreApi.cs @@ -6,7 +6,6 @@ using RestSharp; using IO.Swagger.Client; using IO.Swagger.Model; - namespace IO.Swagger.Api { diff --git a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Api/UserApi.cs b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Api/UserApi.cs index ac4f138c568b..5502fe15da17 100644 --- a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Api/UserApi.cs +++ b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Api/UserApi.cs @@ -6,7 +6,6 @@ using RestSharp; using IO.Swagger.Client; using IO.Swagger.Model; - namespace IO.Swagger.Api { diff --git a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Client/ApiClient.cs b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Client/ApiClient.cs index faf688b55853..58ade0637180 100644 --- a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Client/ApiClient.cs +++ b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Client/ApiClient.cs @@ -19,23 +19,56 @@ namespace IO.Swagger.Client public class ApiClient { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class + /// with default configuration and base path (http://petstore.swagger.io/v2). + /// + public ApiClient() + { + Configuration = Configuration.Default; + RestClient = new RestClient("http://petstore.swagger.io/v2"); + } + + /// + /// Initializes a new instance of the class + /// with default base path (http://petstore.swagger.io/v2). + /// + /// An instance of Configuration. + public ApiClient(Configuration config = null) + { + if (config == null) + Configuration = Configuration.Default; + else + Configuration = config; + + RestClient = new RestClient("http://petstore.swagger.io/v2"); + } + + /// + /// Initializes a new instance of the class + /// with default configuration. /// /// The base path. - public ApiClient(String basePath="http://petstore.swagger.io/v2") + public ApiClient(String basePath = "http://petstore.swagger.io/v2") { if (String.IsNullOrEmpty(basePath)) throw new ArgumentException("basePath cannot be empty"); RestClient = new RestClient(basePath); + Configuration = Configuration.Default; } /// /// Gets or sets the default API client for making HTTP calls. /// /// The default API client. - public static ApiClient Default = new ApiClient(); + public static ApiClient Default = new ApiClient(Configuration.Default); + /// + /// Gets or sets the Configuration. + /// + /// An instance of the Configuration. + public Configuration Configuration { get; set; } + /// /// Gets or sets the RestClient. /// diff --git a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Client/Configuration.cs b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Client/Configuration.cs index fcdc16f44db5..588b106dec9a 100644 --- a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Client/Configuration.cs +++ b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Client/Configuration.cs @@ -109,13 +109,13 @@ namespace IO.Swagger.Client return apiKeyValue; } - private static string _tempFolderPath = Path.GetTempPath(); + private string _tempFolderPath = Path.GetTempPath(); /// /// Gets or sets the temporary folder path to store the files downloaded from the server. /// /// Folder path. - public static String TempFolderPath + public String TempFolderPath { get { return _tempFolderPath; } @@ -141,7 +141,7 @@ namespace IO.Swagger.Client private const string ISO8601_DATETIME_FORMAT = "o"; - private static string _dateTimeFormat = ISO8601_DATETIME_FORMAT; + private string _dateTimeFormat = ISO8601_DATETIME_FORMAT; /// /// Gets or sets the the date time format used when serializing in the ApiClient @@ -151,7 +151,7 @@ namespace IO.Swagger.Client /// No validation is done to ensure that the string you're providing is valid /// /// The DateTimeFormat string - public static String DateTimeFormat + public String DateTimeFormat { get { diff --git a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/Category.cs b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/Category.cs index 03551f9492bc..d9cb6b21005d 100644 --- a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/Category.cs +++ b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/Category.cs @@ -7,8 +7,6 @@ using System.Collections.Generic; using System.Runtime.Serialization; using Newtonsoft.Json; - - namespace IO.Swagger.Model { @@ -124,6 +122,4 @@ namespace IO.Swagger.Model } } - - } diff --git a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/Order.cs b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/Order.cs index 1d214430ec86..2191707bd091 100644 --- a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/Order.cs +++ b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/Order.cs @@ -7,8 +7,6 @@ using System.Collections.Generic; using System.Runtime.Serialization; using Newtonsoft.Json; - - namespace IO.Swagger.Model { @@ -189,6 +187,4 @@ namespace IO.Swagger.Model } } - - } diff --git a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/Pet.cs b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/Pet.cs index ab60577e85af..10c44fb46a7b 100644 --- a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/Pet.cs +++ b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/Pet.cs @@ -7,8 +7,6 @@ using System.Collections.Generic; using System.Runtime.Serialization; using Newtonsoft.Json; - - namespace IO.Swagger.Model { @@ -189,6 +187,4 @@ namespace IO.Swagger.Model } } - - } diff --git a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/Tag.cs b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/Tag.cs index cf77c2470b2d..93210505bf0f 100644 --- a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/Tag.cs +++ b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/Tag.cs @@ -7,8 +7,6 @@ using System.Collections.Generic; using System.Runtime.Serialization; using Newtonsoft.Json; - - namespace IO.Swagger.Model { @@ -124,6 +122,4 @@ namespace IO.Swagger.Model } } - - } diff --git a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/User.cs b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/User.cs index eca977c3b183..1fbd17da993a 100644 --- a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/User.cs +++ b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Model/User.cs @@ -7,8 +7,6 @@ using System.Collections.Generic; using System.Runtime.Serialization; using Newtonsoft.Json; - - namespace IO.Swagger.Model { @@ -221,6 +219,4 @@ namespace IO.Swagger.Model } } - - } diff --git a/samples/client/petstore/csharp/SwaggerClientTest/TestApiClient.cs b/samples/client/petstore/csharp/SwaggerClientTest/TestApiClient.cs index adf59e0ae0ca..f0232c330f04 100644 --- a/samples/client/petstore/csharp/SwaggerClientTest/TestApiClient.cs +++ b/samples/client/petstore/csharp/SwaggerClientTest/TestApiClient.cs @@ -11,7 +11,7 @@ namespace SwaggerClientTest.TestApiClient public void TearDown() { // Reset to default, just in case - Configuration.DateTimeFormat = "o"; + Configuration.Default.DateTimeFormat = "o"; } [Test ()] @@ -29,28 +29,34 @@ namespace SwaggerClientTest.TestApiClient } [Test ()] - public void TestParameterToString_DateTime () - { - ApiClient api = new ApiClient(); + public void TestParameterToStringForDateTime () + { + ApiClient api = new ApiClient (); - // test datetime - DateTime dateUtc = DateTime.Parse("2008-04-10T13:30:00.0000000z", null, System.Globalization.DateTimeStyles.RoundtripKind); - Assert.AreEqual("2008-04-10T13:30:00.0000000Z", api.ParameterToString(dateUtc)); + // test datetime + DateTime dateUtc = DateTime.Parse ("2008-04-10T13:30:00.0000000z", null, System.Globalization.DateTimeStyles.RoundtripKind); + Assert.AreEqual ("2008-04-10T13:30:00.0000000Z", api.ParameterToString (dateUtc)); - // test datetime with no timezone - DateTime dateWithNoTz = DateTime.Parse("2008-04-10T13:30:00.000", null, System.Globalization.DateTimeStyles.RoundtripKind); - Assert.AreEqual("2008-04-10T13:30:00.0000000", api.ParameterToString(dateWithNoTz)); + // test datetime with no timezone + DateTime dateWithNoTz = DateTime.Parse ("2008-04-10T13:30:00.000", null, System.Globalization.DateTimeStyles.RoundtripKind); + Assert.AreEqual ("2008-04-10T13:30:00.0000000", api.ParameterToString (dateWithNoTz)); + } + // The test below only passes when running at -04:00 timezone + [Ignore ()] + public void TestParameterToStringWithTimeZoneForDateTime () + { + ApiClient api = new ApiClient (); // test datetime with a time zone DateTime dateWithTz = DateTime.Parse("2008-04-10T13:30:00.0000000-04:00", null, System.Globalization.DateTimeStyles.RoundtripKind); Assert.AreEqual("2008-04-10T13:30:00.0000000-04:00", api.ParameterToString(dateWithTz)); } [Test ()] - public void TestParameterToString_DateTime_WithUFormat () + public void TestParameterToStringForDateTimeWithUFormat () { // Setup the DateTimeFormat across all of the calls - Configuration.DateTimeFormat = "u"; + Configuration.Default.DateTimeFormat = "u"; ApiClient api = new ApiClient(); // test datetime @@ -59,10 +65,10 @@ namespace SwaggerClientTest.TestApiClient } [Test ()] - public void TestParameterToString_DateTime_WithCustomFormat () + public void TestParameterToStringForDateTimeWithCustomFormat () { // Setup the DateTimeFormat across all of the calls - Configuration.DateTimeFormat = "dd/MM/yy HH:mm:ss"; + Configuration.Default.DateTimeFormat = "dd/MM/yy HH:mm:ss"; ApiClient api = new ApiClient(); // test datetime diff --git a/samples/client/petstore/csharp/SwaggerClientTest/TestConfiguration.cs b/samples/client/petstore/csharp/SwaggerClientTest/TestConfiguration.cs index c72a00066918..2ea6785529a9 100644 --- a/samples/client/petstore/csharp/SwaggerClientTest/TestConfiguration.cs +++ b/samples/client/petstore/csharp/SwaggerClientTest/TestConfiguration.cs @@ -13,7 +13,7 @@ namespace SwaggerClientTest.TestConfiguration public void TearDown () { // Reset to default, just in case - Configuration.DateTimeFormat = "o"; + Configuration.Default.DateTimeFormat = "o"; } [Test ()] @@ -44,15 +44,15 @@ namespace SwaggerClientTest.TestConfiguration { // Should default to the Round-trip Format Specifier - "o" // https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx#Anchor_8 - Assert.AreEqual("o", Configuration.DateTimeFormat); + Assert.AreEqual("o", Configuration.Default.DateTimeFormat); } [Test ()] public void TestDateTimeFormat_UType() { - Configuration.DateTimeFormat = "u"; + Configuration.Default.DateTimeFormat = "u"; - Assert.AreEqual("u", Configuration.DateTimeFormat); + Assert.AreEqual("u", Configuration.Default.DateTimeFormat); } [Test ()] diff --git a/samples/client/petstore/csharp/SwaggerClientTest/bin/Debug/SwaggerClientTest.dll b/samples/client/petstore/csharp/SwaggerClientTest/bin/Debug/SwaggerClientTest.dll index a438e10395475b6b219e30bbe99b06cf8364659c..dbeb4f0ebadc6185dbb278cebe2f41412981ff71 100755 GIT binary patch literal 113152 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

<0NT;M2>X&0QQzzkBw%;N5#v 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 delta 9563 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

<0NT;M2>X&0QQzzkBw%;N5#v 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 delta 9563 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 vqxhB!--H*zwNN>ngs(=o-~v1o-G Date: Mon, 14 Dec 2015 22:26:32 +0800 Subject: [PATCH 56/71] add constructor to configuration --- .../resources/csharp/Configuration.mustache | 39 ++++++++++++++++ .../csharp/IO/Swagger/Client/Configuration.cs | 44 +++++++++++++++++- .../SwaggerClientTest/TestConfiguration.cs | 9 ++++ .../bin/Debug/SwaggerClientTest.dll | Bin 113152 -> 113664 bytes .../bin/Debug/SwaggerClientTest.dll.mdb | Bin 30575 -> 30764 bytes .../obj/Debug/SwaggerClientTest.dll | Bin 113152 -> 113664 bytes .../obj/Debug/SwaggerClientTest.dll.mdb | Bin 30575 -> 30764 bytes 7 files changed, 91 insertions(+), 1 deletion(-) diff --git a/modules/swagger-codegen/src/main/resources/csharp/Configuration.mustache b/modules/swagger-codegen/src/main/resources/csharp/Configuration.mustache index 440288a48327..b5ebd08ba877 100644 --- a/modules/swagger-codegen/src/main/resources/csharp/Configuration.mustache +++ b/modules/swagger-codegen/src/main/resources/csharp/Configuration.mustache @@ -12,6 +12,45 @@ namespace {{packageName}}.Client /// public class Configuration { + ///

+ /// Initializes a new instance of the Configuration class with different settings + /// + /// Api client + /// Dictionary of default HTTP header + /// Username + /// Password + /// accessToken + /// Dictionary of API key + /// Dictionary of API key prefix + /// Temp folder path + /// DateTime format string + public Configuration(ApiClient apiClient, + Dictionary defaultHeader, + string username, + string password, + string accessToken, + Dictionary apiKey, + Dictionary apiKeyPrefix, + string tempFolderPath, + string dateTimeFormat + ) + { + if (apiClient == null) + ApiClient = ApiClient.Default; + else + ApiClient = apiClient; + + Username = username; + Password = password; + AccessToken = accessToken; + ApiKey = apiKey; + ApiKeyPrefix = apiKeyPrefix; + + TempFolderPath = tempFolderPath; + DateTimeFormat = dateTimeFormat; + + } + /// /// Initializes a new instance of the Configuration class. /// diff --git a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Client/Configuration.cs b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Client/Configuration.cs index 588b106dec9a..bfbb9d7479d3 100644 --- a/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Client/Configuration.cs +++ b/samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Client/Configuration.cs @@ -12,11 +12,53 @@ namespace IO.Swagger.Client /// public class Configuration { + /// + /// Initializes a new instance of the Configuration class with different settings + /// + /// Api client + /// Dictionary of default HTTP header + /// Username + /// Password + /// accessToken + /// Dictionary of API key + /// Dictionary of API key prefix + /// Temp folder path + /// DateTime format string + public Configuration(ApiClient apiClient = null, + Dictionary defaultHeader = null, + string username = null, + string password = null, + string accessToken = null, + Dictionary apiKey = null, + Dictionary apiKeyPrefix = null, + string tempFolderPath = null, + string dateTimeFormat = null + ) + { + if (apiClient == null) + ApiClient = ApiClient.Default; + else + ApiClient = apiClient; + + Username = username; + Password = password; + AccessToken = accessToken; + + if (apiKey != null) + ApiKey = apiKey; + if (apiKeyPrefix != null) + ApiKeyPrefix = apiKeyPrefix; + + TempFolderPath = tempFolderPath; + DateTimeFormat = dateTimeFormat; + + } + /// /// Initializes a new instance of the Configuration class. /// /// Api client. - public Configuration(ApiClient apiClient=null) + public Configuration(ApiClient apiClient) { if (apiClient == null) ApiClient = ApiClient.Default; diff --git a/samples/client/petstore/csharp/SwaggerClientTest/TestConfiguration.cs b/samples/client/petstore/csharp/SwaggerClientTest/TestConfiguration.cs index 2ea6785529a9..a72e1a5ed1d2 100644 --- a/samples/client/petstore/csharp/SwaggerClientTest/TestConfiguration.cs +++ b/samples/client/petstore/csharp/SwaggerClientTest/TestConfiguration.cs @@ -55,6 +55,15 @@ namespace SwaggerClientTest.TestConfiguration Assert.AreEqual("u", Configuration.Default.DateTimeFormat); } + [Test ()] + public void TestConstructor() + { + Configuration c = new Configuration (username: "test username", password: "test password"); + Assert.AreEqual (c.Username, "test username"); + Assert.AreEqual (c.Password, "test password"); + + } + [Test ()] public void TestDefautlConfiguration () { diff --git a/samples/client/petstore/csharp/SwaggerClientTest/bin/Debug/SwaggerClientTest.dll b/samples/client/petstore/csharp/SwaggerClientTest/bin/Debug/SwaggerClientTest.dll index dbeb4f0ebadc6185dbb278cebe2f41412981ff71..1cc6bc94f0c97cc2eb0e3c881f9499928d0f3982 100755 GIT binary patch delta 15330 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 YLBGR&@mG*2t{LQpo+Z%deslK!0EW+_G5`Po delta 8599 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 diff --git a/samples/client/petstore/csharp/SwaggerClientTest/obj/Debug/SwaggerClientTest.dll b/samples/client/petstore/csharp/SwaggerClientTest/obj/Debug/SwaggerClientTest.dll index dbeb4f0ebadc6185dbb278cebe2f41412981ff71..1cc6bc94f0c97cc2eb0e3c881f9499928d0f3982 100755 GIT binary patch delta 15330 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 YLBGR&@mG*2t{LQpo+Z%deslK!0EW+_G5`Po delta 8599 zcmZ9R30xJ`9>>q0t8fQIA1;|hxu&M|dYKtX?pm6eW|pSrR=(F01q2l|^nx4i3d1I= zxZn!13Zf!zx#IqE#U(8>1+2_9^?mQ<4uSgl@%#RlnRDjMnHj82cci>bhSpEDJZawY zmtO5u#h>+s!=h`cB_D=e8rxLAckx@_K&AXBd5ux34t{@%QbD+tEp}cjN^PWmx*kdU zAK$>tq4729ZaKZiJ$clFlohuYr+4;!_oP}8K5Oz&UF;n%tg_ZiC^U0i?ycgyCm$8SgGeV(93J! zu!J7ADZ18ob$!LnO>;~fueOcfKHeB5(73#|jz5l9*T!GBRz#lhr%tU#)&-cR-|f(1 z^k3uElksyW7>6Z@)bpm#)y>s0e}dXNp}<-)j(gd9+zMLi4y*t5yVeP~x_P)YXh8F+ z3F`EO5}HLh`j7SV^`BI+%vt)>cUxFOeAEJ;g+9h8Evy&Y&~b;4D)iY|navleJCs7R z7A+i4`KZ%A|Ff5zObx`VK9zrHnp2sND)+flS!rxN)k{wEeARs41-=ynIGJqOCQeDd zD%p31uWD<%=T4@U*5+57a(q>;@0QADTei8=AzyXa_lU3lp{Hk;E57Py-y4-3ou!`p z*Bq+3Hqo4t{nQG-6hC9A-crANMXizMw9QX#_uJv87kajHI^(C#`knLB?|XK%ESsoe zC#FoSIL2J%a?B?ts*@8>RaPo4$9!v|x;?S9dbWu<)L+f?pXG0yrQ&MLG5#vne|hz6 zb90)%O84Jv&sxl;H>{W5#JtB}?e*VR*=)tDbFR zo)e(v280C|lX$=4yzv1lAt14O_EmFcfXWKU4zRDk+0?_@+|;~3KphA;SlMjLwltRn zs7nEt1N5OCM>+iwpdJQ13eb0TY|#AtBz0lZ#Yx71|E;p#=6jRW{Yeid=?^>p$1!5E z(kDmi|MnW|7&1l8n-Za)@TzaQHAUT?QaYvLXsu#nyrj(uRC5Ev0;^@4Xz_t6AuzEr zYg^wIT4tci3e2vaeNEdRs15`ktjyXL@)fNlP+bbVTqSGaf}3l91gg7%e^#b#>-(BE zKS(VIS{P(Z!j}D~mK>y31f^7Fy=+USPS#=W!AQkO|+{)>c^mK z6382B)p_w$rB98VY79NH%Kp~wPE~(Sy;oVQy58EdX)1hL zgdWjptkb4xDs5W&H2rC(Z!9t2spRk0e^+rj=PKLVd1kPh6+AoGs8nok=Y(LD7@Sl+ z+r&95SY-$2RAwu-xATEubujo)^=xzJOTp@L@D;M690K&Ko!fP}8>}7$Kd$Vn`p7zG zPggn9bEg}#sQSn{ADga@Pd_nTAK0ax)2-?1_Vm)}`ob<9Evsj!O*3+5R2<_{<(gc6 znxTH4aig+QaZN7IW~dNLsKw~7cmugaSyZ$orZQ{0re-c1Eoze`t$MbV%Px!BZP{bb zT3jj~+2$^1Eb6S~TxGLur?qw|wWu;nd1cnNd78P*3K2CsMCM?&SDuT>R%qptKqfIn zlKw8(HdbSoTryiiB=5OG3yaH9QpZB%_}`W8*1g!wtuckm7ha(ziyMw zPl#sCl-YV|w}!1B&lL67OnHLY$Ddl|W#JMxOH}+UNtmU--aSm)N>ngQw$0MFcc0qq z;A~MRX3GW4c4#eA9qZJcYaO1$JmyI89DQ()Q0+QV^jwLVt6%NWTq~O^>cL!jI9GS= z8K%XBv65ku7p5onT%&E6C+hoovVWfbaqpM)Z+nf@&dwKAI$z4>>&JUpw2}p)o-UAQ z3-lo$^wEA=C~CnXS-42w@WE6qZ;_}=i==!}_Uj)u6m9EbQISg|Y6++6rJY+Us%)v0 zFV*9ExA9oJOjPDF$-=DjX3DPT;S0;;;xhe8?-#UEqOxUDzD$3{!HdF0Z3vf*;d;M5 zA8O}`9)-)}a6PflTiS*QQH2q*GeSSpr=514=+6kb7opevsGUc$E-FKpOw2w^?ep*j zT`ubSsE=N7FC{9|rQF)U!hLQ1_}4bo=Qjm?*+-4FMUkSyBPAkI&;O`Rn|(xwBIPh< zTkP7Vw$fl|JL~UUj;@~d9cw?J@-R{!Me4QsdT7g|*ga7aAEl4#>ruyxb9(W&W4rcs zhqkY)FYNoeR!GOmC^;3S7xjJJt-sW#KJ%S+UUi4IYd7?ry84s8?X;w5QM;pMPqgm& zaT7~)jHs9xiN$PFsAH;az28mi>?BhZBfFj}{IkwkGUsCC{NIK8)+0L9`Hjr)G4jWA zg&uVl#EM!ND~mAu81B|18r4}9J4n>(SXuL2rDdJ%WOl?#p}k->h1PH|Nj-;2wK!0# zt;zqW{17W=>nTx`$Y_#znq=4T%s`hos!jYqSnMoDrQZYifTw*4s72+ z@<`>!$=0fsc9gpH=p!dco{W=IaeAFkUi2s>DvOhHd#82WCGnz`#>=vJy~igJ15=1r z#!DJzjJrL7i%F0|%r@?cn#Q=tNF7g*6ICn5xHn1unjp6l^j7^Fd(24`H8)YhFypjo zaC)L_PSnTrUpc&pXjh^fsnT#ON!0BmDaCB#UUM|YeM;(Cl7u8zsTkwNl3boFarTuM=jt(OkW7uSzfhbOeT|LR;pyD z>gAuk=uu2`G*yn-JFSaQ2A8MGom9Q~pwxk({A+RMT3L)4Gs{@VD{-Am_l$KH&2VOFGf!^-_Qt z?_gX0zRtrsn!jOa zt#+5%uV@Y#v}A6SENkaKXr)1<_HoOP@@={$<*5|*wP44&Z` zOSC*);xJ>Zet5_t&-FwbGGrrWj8&K^YG7;hJc6C_V&%Bf6!>6Z<( zQlhdgB` z9vfAY*>uxX?X_=;c`1iSCP$WI_IaBM;B7gwJx4De>Tf9~I+`QLsx%zP6?HII4q>(# znM^B;`(e63@?x%(RIk}*WV%oKL9RTkteQ=~R{s#0qPFmx&=!fotS5Knu9@-)wr-Jv zEqdv&0Lx*bBU_}{-eGOnpT`?6PYz=C8KoF^&2*mRg*>@fy=Khl9_jme@}RP6Hr=XO zeT^dXd6M!a8mpX99zlM-Y|Yni4-fd_5Ygd$Ib!dy&glECqV{i<1DJhAD~-EmI!E&S zR=H5UX3XeM()YH?{jGZLS4~^%1^kXyAW@k0Jl0e1fC~#`r#)4J+xpZ|@6yj*U)H~- z{_=>imgAI86v)Xc2i@Gp*KeEL!tC?eV0=4Ff02B$O`cY-8S{zV&I7q!;;@P%&8FX+ zY%Anre~p{AP|Mpc`SupuJv&Eme!E=QuGb#v_r-0Z((O`a@33CRPdh~YyhCna_8Fy` z?Qam%1CkGS$fN2tV@8pM+>kG2> zRcV-A#3!Uk=3@4-(~K{gDTZWhku0xXGsey)ol_*al~uFpS;bdvnz0%usGTg5Q}!0y zYTPCGvq938R`9;_+QS)}me9V|~#BNdgZi&R~Gb%7XYo;|MQ+LbS>NR6VyGZZe zEqiwBGREEGGSQXYa@F2zUFey6_@~SsnY~AUcT9+96jAgZiNTDqllJn#-zzIH``AUs zr_Gc}GHb77@72r4G|-BPj_#FXdv({ZTX@_ey1iFQ?Z+`zjo5u`mVFYpFT3B@4b7G> z-%+Xwda9IT0RC_E3|@+dAjN;wTZ1Pcfw$pV$N@fqA3!Gf27U?EfS=%ZQBAmB2c?{m zBRmA}gq&c1d~640QD%a4f-t1P2k~vl8NP>KLN4&z?qfKfG&Es+gc2K?6^veu3-5Z^6w_1GpdF8NC3{#fPGX z@P2$HdJ(>gpGJ+~`*<00hh5)eMbJxdbKD(y!0+MzLN8kg`U4-JSKzVuaMT$74);e* z;Bb5%Y6`E#lTb5w2cCnP!>8~=s0Dlzzk*(c2Xs{GG29X!4}XPP!Sis-RDQH3xQ9of z*Wl4!tO#lYe~0^^ws1H;54{er#got*@D4l&{S!WgA3|@!H}NazU+^>h9(oII@IJQ@ zwG(A=Yzs6)Z&T=od!qL6VEhyG4m<(>26cdE;nUE&@UM6j@`N2b@&6Ry_uyu5J=76i zjK7Jz;0O2y^gdj-GaIxs_rDWCYl6n8Gu#<}2X%o5;eAn8cpN?&b%WRA!KgdD58r}% zz*q5;s3+{+g?#|`f``E!&Ic{9$|Ht8fm`E^QGd7_?uiD#L-9|of&=hz$TE;%5ikpV2Cu;r&>*-F&qbfZ zXYixw3-}Ix0}Y0Ky0MIC2)r1dfxd({;fZJ{{C;<(w!_2VLU_1U@R{yB|3?YFA{gC+ zM+uF97vs~=NciQRO69|&;KOilG#VbzOQ~{r415+2L0`jdK45d9Z{SV19~uiE`H)8# z{Tp`g&C0?55ev^Z!Q1Ft3Zw9^(0^eI?uW*~#rP)V4Zqw+slVXy@L;$rngB=Ofyl?& zk7prY_zGTv{NQK!9W)X4{D@6z;fFtgH~ujSfEVH4p-FHio`5F9Zhd*lz*FG)a8DEn zXW`3H5PTTlji$oa@e61g`~<&?zJp)*m^UX1hAnRbEzxv>-gp-@1O6{Q1XAcl+oI+0Df~E!gG=#i zC?3`ZD)j_Tur6;~f<`D2?u>h(B=|l)1SP}HpYhp5E8rHmJ4%7O;_cB&cr-o$t%4`v z6VYn8`5;yVUITZ4-$tqM0NnBcKh_eA$48-c@De;2t%p!#nVvXb*fGFGhRe+xQi<4|X2PK7+r9->?w4 zqx}S3@lNOfybT|K4#G$A!{`wFD}Kou!{%WuBYXsI3%`hp;m)`hItmxypP*xKF@6Xg zhi~E~$Z~?fX}D4k2~NUo;D+cF+zIc9PQzRAe&~Pj5&R(f0saNQh|a){Un%tfJ`4W~ zegU0>d*EHsdH5p!8M*+Mf5r2Eo8TgW%Lsn)giGMp;Fr)P_+$J%bQvCr4@Xzvv$!w1 z3g5ziK|jJyBl&Fyz6QSvH$>Or{`foSCwL4#68&s_|KA7v(G3dDqj=2FFK|oT9o>X` z;vLYh@PF_@=oUN;4@9@&nxlD9!KLtva065Zx5rzfa(E!#6WxI)<6}PO$8QAl@Hyyr q*li3i68I0e1>6+fg}dVI(Vy@Ld;q!!FT{P&eK-k^AES2+{QdttgMaY= From fbf4d0e41922fdb26f92f35039f3f4032656f725 Mon Sep 17 00:00:00 2001 From: Artyom Date: Tue, 15 Dec 2015 10:51:04 +0200 Subject: [PATCH 57/71] Fixed ArgumentOutOfRangeException If the list is empty you get the ArgumentOutOfRangeException when calling flattenString.Remove(flattenString.Length - 1). Also using a StringBuilder is the prefered way to concatenate strings in a loop. --- .../src/main/resources/csharp/ApiClient.mustache | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/modules/swagger-codegen/src/main/resources/csharp/ApiClient.mustache b/modules/swagger-codegen/src/main/resources/csharp/ApiClient.mustache index 707ce9eb5602..1ab3c939e4cf 100644 --- a/modules/swagger-codegen/src/main/resources/csharp/ApiClient.mustache +++ b/modules/swagger-codegen/src/main/resources/csharp/ApiClient.mustache @@ -163,13 +163,14 @@ namespace {{packageName}}.Client return ((DateTime)obj).ToString (Configuration.DateTimeFormat); else if (obj is IList) { - string flattenString = ""; - string separator = ","; + var flattenedString = new StringBuilder(); foreach (var param in (IList)obj) { - flattenString += param.ToString() + separator; + if (flattenedString.Length > 0) + flattenedString.Append(","); + flattenedString.Append(param); } - return flattenString.Remove(flattenString.Length - 1);; + return flattenedString.ToString(); } else return Convert.ToString (obj); From 3f3e444ab19b46ff404da4a09831ba445184c09e Mon Sep 17 00:00:00 2001 From: xhh Date: Tue, 15 Dec 2015 19:38:04 +0800 Subject: [PATCH 58/71] Some clean-ups for the Javascript client codegen --- .../languages/JavascriptClientCodegen.java | 108 +++--------------- .../main/resources/Javascript/api.mustache | 4 - .../Javascript/generatedAnnotation.mustache | 1 - .../javascript/src/scripts/rest/api/PetApi.js | 4 - .../src/scripts/rest/api/StoreApi.js | 4 - .../src/scripts/rest/api/UserApi.js | 4 - .../javascript/src/scripts/rest/model/Pet.js | 2 +- 7 files changed, 14 insertions(+), 113 deletions(-) delete mode 100644 modules/swagger-codegen/src/main/resources/Javascript/generatedAnnotation.mustache diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavascriptClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavascriptClientCodegen.java index 51ef135ae0dc..c17b466866c1 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavascriptClientCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavascriptClientCodegen.java @@ -34,15 +34,8 @@ import org.slf4j.LoggerFactory; public class JavascriptClientCodegen extends DefaultCodegen implements CodegenConfig { private static final Logger LOGGER = LoggerFactory.getLogger(JavascriptClientCodegen.class); - protected String invokerPackage = "io.swagger.client"; - protected String groupId = "io.swagger"; - protected String artifactId = "swagger-java-client"; - protected String artifactVersion = "1.0.0"; protected String sourceFolder = "src"; protected String localVariablePrefix = ""; - protected boolean fullJavaUtil = false; - protected String javaUtilPrefix = ""; - protected Boolean serializableModel = false; public JavascriptClientCodegen() { super(); @@ -80,14 +73,8 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo instantiationTypes.put("map", "HashMap"); cliOptions.add(new CliOption(CodegenConstants.INVOKER_PACKAGE, CodegenConstants.INVOKER_PACKAGE_DESC)); - cliOptions.add(new CliOption(CodegenConstants.GROUP_ID, CodegenConstants.GROUP_ID_DESC)); - cliOptions.add(new CliOption(CodegenConstants.ARTIFACT_ID, CodegenConstants.ARTIFACT_ID_DESC)); - cliOptions.add(new CliOption(CodegenConstants.ARTIFACT_VERSION, CodegenConstants.ARTIFACT_VERSION_DESC)); cliOptions.add(new CliOption(CodegenConstants.SOURCE_FOLDER, CodegenConstants.SOURCE_FOLDER_DESC)); cliOptions.add(new CliOption(CodegenConstants.LOCAL_VARIABLE_PREFIX, CodegenConstants.LOCAL_VARIABLE_PREFIX_DESC)); - cliOptions.add(new CliOption(CodegenConstants.SERIALIZABLE_MODEL, CodegenConstants.SERIALIZABLE_MODEL_DESC)); - cliOptions.add(new CliOption("fullJavaUtil", "whether to use fully qualified name for classes under java.util (default to false)")); - } @Override @@ -108,9 +95,7 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo @Override public void processOpts() { super.processOpts(); - - typeMapping.put("array", "Array"); - + typeMapping.put("array", "Array"); } @Override @@ -198,84 +183,42 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo @Override public String toDefaultValue(Property p) { if (p instanceof ArrayProperty) { - final ArrayProperty ap = (ArrayProperty) p; - final String pattern; - //if (fullJavaUtil) { - // pattern = "new ArrayList()"; - //} else { - // pattern = "new ArrayList<%s>()"; - //} - - pattern = "new Array()"; - return String.format(pattern, getTypeDeclaration(ap.getItems())); + return "[]"; } else if (p instanceof MapProperty) { - final MapProperty ap = (MapProperty) p; - final String pattern; - if (fullJavaUtil) { - pattern = "new java.util.HashMap()"; - } else { - pattern = "new HashMap()"; - } - return String.format(pattern, getTypeDeclaration(ap.getAdditionalProperties())); - + return "{}"; } else if (p instanceof LongProperty) { LongProperty dp = (LongProperty) p; if (dp.getDefault() != null) { return dp.getDefault().toString()+"l"; } return "null"; - + // added for Javascript } else if (p instanceof RefProperty) { RefProperty rp = (RefProperty)p; - System.out.println("rp: " + rp.getName() + rp.getAccess() + rp.getDescription() + rp.getExample() + rp.getFormat() + rp.getSimpleRef() + rp.getTitle() + rp.getType()); - - return "new " +rp.getSimpleRef() + "()"; + return "new " +rp.getSimpleRef() + "()"; } - - System.out.println("property: " + p); - + return super.toDefaultValue(p); } - + @Override public String toDefaultValueWithParam(String name, Property p) { if (p instanceof ArrayProperty) { - final ArrayProperty ap = (ArrayProperty) p; - final String pattern; -// if (fullJavaUtil) { -// pattern = "new java.util.ArrayList<%s>()"; -// } else { -// pattern = "new ArrayList<%s>()" ; -// } - pattern = " = new Array()" ; - - return String.format(pattern, getTypeDeclaration(ap.getItems()))+ ";"; + return " = new Array();"; } else if (p instanceof MapProperty) { - final MapProperty ap = (MapProperty) p; - final String pattern; - if (fullJavaUtil) { - pattern = " = new java.util.HashMap()"; - } else { - pattern = "new HashMap()"; - } - return String.format(pattern, getTypeDeclaration(ap.getAdditionalProperties()))+ ";"; - + return " = {}"; } else if (p instanceof LongProperty) { LongProperty dp = (LongProperty) p; return " = data." + name + ";"; - + // added for Javascript } else if (p instanceof RefProperty) { RefProperty rp = (RefProperty)p; - System.out.println("rp: " + rp.getName() + rp.getAccess() + rp.getDescription() + rp.getExample() + rp.getFormat() + rp.getSimpleRef() + rp.getTitle() + rp.getType()); - - return ".constructFromObject(data." + name + ");"; + return ".constructFromObject(data." + name + ");"; } - - System.out.println("property: " + p); - + return super.toDefaultValueWithParam(name, p); } @@ -449,7 +392,7 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo } } } - + if(removedChildEnum) { // If we removed an entry from this model's vars, we need to ensure hasMore is updated int count = 0, numVars = codegenProperties.size(); @@ -464,22 +407,6 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo return codegenModel; } - public void setInvokerPackage(String invokerPackage) { - this.invokerPackage = invokerPackage; - } - - public void setGroupId(String groupId) { - this.groupId = groupId; - } - - public void setArtifactId(String artifactId) { - this.artifactId = artifactId; - } - - public void setArtifactVersion(String artifactVersion) { - this.artifactVersion = artifactVersion; - } - public void setSourceFolder(String sourceFolder) { this.sourceFolder = sourceFolder; } @@ -488,15 +415,6 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo this.localVariablePrefix = localVariablePrefix; } - - public Boolean getSerializableModel() { - return serializableModel; - } - - public void setSerializableModel(Boolean serializableModel) { - this.serializableModel = serializableModel; - } - private String sanitizePackageName(String packageName) { packageName = packageName.trim(); packageName = packageName.replaceAll("[^a-zA-Z0-9_\\.]", "_"); diff --git a/modules/swagger-codegen/src/main/resources/Javascript/api.mustache b/modules/swagger-codegen/src/main/resources/Javascript/api.mustache index f7bc498ff189..dd115aaa45c1 100644 --- a/modules/swagger-codegen/src/main/resources/Javascript/api.mustache +++ b/modules/swagger-codegen/src/main/resources/Javascript/api.mustache @@ -1,7 +1,3 @@ -/* - * {{>generatedAnnotation}} - */ - //export module if ( typeof define === "function" && define.amd ) { define(['jquery'], function($) { diff --git a/modules/swagger-codegen/src/main/resources/Javascript/generatedAnnotation.mustache b/modules/swagger-codegen/src/main/resources/Javascript/generatedAnnotation.mustache deleted file mode 100644 index 49110fc1ad93..000000000000 --- a/modules/swagger-codegen/src/main/resources/Javascript/generatedAnnotation.mustache +++ /dev/null @@ -1 +0,0 @@ -@javax.annotation.Generated(value = "{{generatorClass}}", date = "{{generatedDate}}") \ No newline at end of file diff --git a/samples/client/petstore/javascript/src/scripts/rest/api/PetApi.js b/samples/client/petstore/javascript/src/scripts/rest/api/PetApi.js index bf35463dc1a5..5b4f65234137 100644 --- a/samples/client/petstore/javascript/src/scripts/rest/api/PetApi.js +++ b/samples/client/petstore/javascript/src/scripts/rest/api/PetApi.js @@ -1,7 +1,3 @@ -/* - * @javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavascriptClientCodegen", date = "2015-12-09T16:07:21.000+07:00") - */ - //export module if ( typeof define === "function" && define.amd ) { define(['jquery'], function($) { diff --git a/samples/client/petstore/javascript/src/scripts/rest/api/StoreApi.js b/samples/client/petstore/javascript/src/scripts/rest/api/StoreApi.js index 5487b1c386ed..e27494c7924d 100644 --- a/samples/client/petstore/javascript/src/scripts/rest/api/StoreApi.js +++ b/samples/client/petstore/javascript/src/scripts/rest/api/StoreApi.js @@ -1,7 +1,3 @@ -/* - * @javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavascriptClientCodegen", date = "2015-12-09T16:07:21.000+07:00") - */ - //export module if ( typeof define === "function" && define.amd ) { define(['jquery'], function($) { diff --git a/samples/client/petstore/javascript/src/scripts/rest/api/UserApi.js b/samples/client/petstore/javascript/src/scripts/rest/api/UserApi.js index 30c797cf25f2..ecd9707fa91e 100644 --- a/samples/client/petstore/javascript/src/scripts/rest/api/UserApi.js +++ b/samples/client/petstore/javascript/src/scripts/rest/api/UserApi.js @@ -1,7 +1,3 @@ -/* - * @javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavascriptClientCodegen", date = "2015-12-09T16:07:21.000+07:00") - */ - //export module if ( typeof define === "function" && define.amd ) { define(['jquery'], function($) { diff --git a/samples/client/petstore/javascript/src/scripts/rest/model/Pet.js b/samples/client/petstore/javascript/src/scripts/rest/model/Pet.js index b97907396f18..259857334502 100644 --- a/samples/client/petstore/javascript/src/scripts/rest/model/Pet.js +++ b/samples/client/petstore/javascript/src/scripts/rest/model/Pet.js @@ -66,7 +66,7 @@ var Pet = function Pet(photoUrls, name) { /** * datatype: Array **/ - self.tags = new Array(); + self.tags = []; /** * pet status in the store From 199c4f70adf5e0c800f4f02f0455daeaf68d1521 Mon Sep 17 00:00:00 2001 From: xhh Date: Tue, 15 Dec 2015 22:57:02 +0800 Subject: [PATCH 59/71] Add some config options to Javascript client codegen --- .../io/swagger/codegen/DefaultCodegen.java | 10 +++ .../languages/ClojureClientCodegen.java | 4 -- .../languages/JavascriptClientCodegen.java | 72 ++++++++++++++++++- samples/client/petstore/javascript/.gitignore | 1 + 4 files changed, 81 insertions(+), 6 deletions(-) create mode 100644 samples/client/petstore/javascript/.gitignore diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/DefaultCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/DefaultCodegen.java index 53c0e6350b0d..cbc1f80fc0b9 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/DefaultCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/DefaultCodegen.java @@ -1823,6 +1823,16 @@ public class DefaultCodegen { return word; } + /** + * Dashize the given word. + * + * @param word The word + * @return The dashized version of the word, e.g. "my-name" + */ + protected String dashize(String word) { + return underscore(word).replaceAll("[_ ]", "-"); + } + /** * Generate the next name for the given name, i.e. append "2" to the base name if not ending with a number, * otherwise increase the number by 1. For example: diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ClojureClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ClojureClientCodegen.java index a850785a7dbb..c8b581b3d3a4 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ClojureClientCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ClojureClientCodegen.java @@ -199,8 +199,4 @@ public class ClojureClientCodegen extends DefaultCodegen implements CodegenConfi protected String namespaceToFolder(String ns) { return ns.replace(".", File.separator).replace("-", "_"); } - - protected String dashize(String s) { - return underscore(s).replaceAll("[_ ]", "-"); - } } diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavascriptClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavascriptClientCodegen.java index c17b466866c1..840cf88fbd85 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavascriptClientCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavascriptClientCodegen.java @@ -11,7 +11,7 @@ import io.swagger.codegen.CodegenProperty; import io.swagger.codegen.CodegenType; import io.swagger.codegen.DefaultCodegen; import io.swagger.codegen.SupportingFile; -import io.swagger.models.Model; +import io.swagger.models.*; import io.swagger.models.properties.ArrayProperty; import io.swagger.models.properties.LongProperty; import io.swagger.models.properties.MapProperty; @@ -34,6 +34,15 @@ import org.slf4j.LoggerFactory; public class JavascriptClientCodegen extends DefaultCodegen implements CodegenConfig { private static final Logger LOGGER = LoggerFactory.getLogger(JavascriptClientCodegen.class); + private static final String PROJECT_NAME = "projectName"; + private static final String PROJECT_DESCRIPTION = "projectDescription"; + private static final String PROJECT_VERSION = "projectVersion"; + private static final String PROJECT_LICENSE_NAME = "projectLicenseName"; + + protected String projectName = null; + protected String projectDescription = null; + protected String projectVersion = null; + protected String sourceFolder = "src"; protected String localVariablePrefix = ""; @@ -72,9 +81,16 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo instantiationTypes.put("array", "Array"); instantiationTypes.put("map", "HashMap"); - cliOptions.add(new CliOption(CodegenConstants.INVOKER_PACKAGE, CodegenConstants.INVOKER_PACKAGE_DESC)); cliOptions.add(new CliOption(CodegenConstants.SOURCE_FOLDER, CodegenConstants.SOURCE_FOLDER_DESC)); cliOptions.add(new CliOption(CodegenConstants.LOCAL_VARIABLE_PREFIX, CodegenConstants.LOCAL_VARIABLE_PREFIX_DESC)); + cliOptions.add(new CliOption(PROJECT_NAME, + "name of the project (Default: generated from info.title or \"swagger-js-client\")")); + cliOptions.add(new CliOption(PROJECT_DESCRIPTION, + "description of the project (Default: using info.description or \"Client library of \")")); + cliOptions.add(new CliOption(PROJECT_VERSION, + "version of the project (Default: using info.version or \"1.0.0\")")); + cliOptions.add(new CliOption(PROJECT_LICENSE_NAME, + "name of the license the project uses (Default: using info.license.name)")); } @Override @@ -98,6 +114,58 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo typeMapping.put("array", "Array"); } + @Override + public void preprocessSwagger(Swagger swagger) { + super.preprocessSwagger(swagger); + + if (additionalProperties.containsKey(PROJECT_NAME)) { + projectName = ((String) additionalProperties.get(PROJECT_NAME)); + } + if (additionalProperties.containsKey(PROJECT_DESCRIPTION)) { + projectDescription = ((String) additionalProperties.get(PROJECT_DESCRIPTION)); + } + if (additionalProperties.containsKey(PROJECT_VERSION)) { + projectVersion = ((String) additionalProperties.get(PROJECT_VERSION)); + } + + if (swagger.getInfo() != null) { + Info info = swagger.getInfo(); + if (projectName == null && info.getTitle() != null) { + // when projectName is not specified, generate it from info.title + projectName = dashize(info.getTitle()); + } + if (projectVersion == null) { + // when projectVersion is not specified, use info.version + projectVersion = info.getVersion(); + } + if (projectDescription == null) { + // when projectDescription is not specified, use info.description + projectDescription = info.getDescription(); + } + if (info.getLicense() != null) { + License license = info.getLicense(); + if (additionalProperties.get(PROJECT_LICENSE_NAME) == null) { + additionalProperties.put(PROJECT_LICENSE_NAME, license.getName()); + } + } + } + + // default values + if (projectName == null) { + projectName = "swagger-js-client"; + } + if (projectVersion == null) { + projectVersion = "1.0.0"; + } + if (projectDescription == null) { + projectDescription = "Client library of " + projectName; + } + + additionalProperties.put(PROJECT_NAME, projectName); + additionalProperties.put(PROJECT_DESCRIPTION, escapeText(projectDescription)); + additionalProperties.put(PROJECT_VERSION, projectVersion); + } + @Override public String escapeReservedWord(String name) { return "_" + name; diff --git a/samples/client/petstore/javascript/.gitignore b/samples/client/petstore/javascript/.gitignore new file mode 100644 index 000000000000..2ccbe4656c60 --- /dev/null +++ b/samples/client/petstore/javascript/.gitignore @@ -0,0 +1 @@ +/node_modules/ From 625e712d7b75608c17b01cc0f2eed8085f2be131 Mon Sep 17 00:00:00 2001 From: xhh Date: Tue, 15 Dec 2015 22:58:15 +0800 Subject: [PATCH 60/71] Javascript: add package.json --- .../src/main/resources/Javascript/package.mustache | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 modules/swagger-codegen/src/main/resources/Javascript/package.mustache diff --git a/modules/swagger-codegen/src/main/resources/Javascript/package.mustache b/modules/swagger-codegen/src/main/resources/Javascript/package.mustache new file mode 100644 index 000000000000..7c9d45a3e6d2 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Javascript/package.mustache @@ -0,0 +1,13 @@ +{ + "name": "{{{projectName}}}", + "version": "{{{projectVersion}}}", + "description": "{{{projectDescription}}}",{{#projectLicenseName}} + "license": "{{{projectLicenseName}}}",{{/projectLicenseName}} + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "dependencies": { + "jquery": "^2.1.4" + } +} From 10885790f8f7f62caf890cba415e872a99019aac Mon Sep 17 00:00:00 2001 From: Tomek Cejner Date: Wed, 16 Dec 2015 14:56:37 +0100 Subject: [PATCH 61/71] Bumped alamofire to 3.1.x --- .../swagger-codegen/src/main/resources/swift/Podspec.mustache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/swagger-codegen/src/main/resources/swift/Podspec.mustache b/modules/swagger-codegen/src/main/resources/swift/Podspec.mustache index 5cf337ad6f2a..d156ef144176 100644 --- a/modules/swagger-codegen/src/main/resources/swift/Podspec.mustache +++ b/modules/swagger-codegen/src/main/resources/swift/Podspec.mustache @@ -16,5 +16,5 @@ Pod::Spec.new do |s| s.documentation_url = '{{podDocumentationURL}}'{{/podDocumentationURL}} s.source_files = '{{projectName}}/Classes/Swaggers/**/*.swift'{{#usePromiseKit}} s.dependency 'PromiseKit', '~> 2.1'{{/usePromiseKit}} - s.dependency 'Alamofire', '~> 3.0.0' + s.dependency 'Alamofire', '~> 3.1.0' end From 2c1d8b19d287dc3fcca033dc8c1efacc180ae749 Mon Sep 17 00:00:00 2001 From: xhh Date: Wed, 16 Dec 2015 23:51:48 +0800 Subject: [PATCH 62/71] Make Javascript client a Node.js (NPM) module --- .../languages/JavascriptClientCodegen.java | 118 ++++++++++++------ .../main/resources/Javascript/api.mustache | 17 ++- .../main/resources/Javascript/index.mustache | 10 ++ .../main/resources/Javascript/model.mustache | 16 ++- .../resources/Javascript/package.mustache | 2 +- .../client/petstore/javascript/package.json | 13 ++ .../src/{scripts/rest => }/api/PetApi.js | 22 +++- .../src/{scripts/rest => }/api/StoreApi.js | 25 ++-- .../src/{scripts/rest => }/api/UserApi.js | 16 ++- .../client/petstore/javascript/src/index.js | 22 ++++ .../src/{scripts/rest => }/model/Category.js | 20 ++- .../src/{scripts/rest => }/model/Order.js | 28 +++-- .../src/{scripts/rest => }/model/Pet.js | 22 +++- .../src/{scripts/rest => }/model/Tag.js | 20 ++- .../src/{scripts/rest => }/model/User.js | 20 ++- 15 files changed, 286 insertions(+), 85 deletions(-) create mode 100644 modules/swagger-codegen/src/main/resources/Javascript/index.mustache create mode 100644 samples/client/petstore/javascript/package.json rename samples/client/petstore/javascript/src/{scripts/rest => }/api/PetApi.js (96%) rename samples/client/petstore/javascript/src/{scripts/rest => }/api/StoreApi.js (93%) rename samples/client/petstore/javascript/src/{scripts/rest => }/api/UserApi.js (97%) create mode 100644 samples/client/petstore/javascript/src/index.js rename samples/client/petstore/javascript/src/{scripts/rest => }/model/Category.js (69%) rename samples/client/petstore/javascript/src/{scripts/rest => }/model/Order.js (85%) rename samples/client/petstore/javascript/src/{scripts/rest => }/model/Pet.js (85%) rename samples/client/petstore/javascript/src/{scripts/rest => }/model/Tag.js (69%) rename samples/client/petstore/javascript/src/{scripts/rest => }/model/User.js (89%) diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavascriptClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavascriptClientCodegen.java index 840cf88fbd85..62bc42bf21d2 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavascriptClientCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavascriptClientCodegen.java @@ -35,11 +35,13 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo private static final Logger LOGGER = LoggerFactory.getLogger(JavascriptClientCodegen.class); private static final String PROJECT_NAME = "projectName"; + private static final String MODULE_NAME = "moduleName"; private static final String PROJECT_DESCRIPTION = "projectDescription"; private static final String PROJECT_VERSION = "projectVersion"; private static final String PROJECT_LICENSE_NAME = "projectLicenseName"; protected String projectName = null; + protected String moduleName = null; protected String projectDescription = null; protected String projectVersion = null; @@ -52,41 +54,44 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo modelTemplateFiles.put("model.mustache", ".js"); apiTemplateFiles.put("api.mustache", ".js"); templateDir = "Javascript"; - apiPackage = "scripts/rest/api"; - modelPackage = "scripts/rest/model"; + apiPackage = "api"; + modelPackage = "model"; + // reference: http://www.w3schools.com/js/js_reserved.asp reservedWords = new HashSet( Arrays.asList( - "abstract", "continue", "for", "new", "switch", "assert", - "default", "if", "package", "synchronized", "boolean", "do", "goto", "private", - "this", "break", "double", "implements", "protected", "throw", "byte", "else", - "import", "public", "throws", "case", "enum", "instanceof", "return", "transient", - "catch", "extends", "int", "short", "try", "char", "final", "interface", "static", - "void", "class", "finally", "long", "strictfp", "volatile", "const", "float", - "native", "super", "while") + "abstract", "arguments", "boolean", "break", "byte", + "case", "catch", "char", "class", "const", + "continue", "debugger", "default", "delete", "do", + "double", "else", "enum", "eval", "export", + "extends", "false", "final", "finally", "float", + "for", "function", "goto", "if", "implements", + "import", "in", "instanceof", "int", "interface", + "let", "long", "native", "new", "null", + "package", "private", "protected", "public", "return", + "short", "static", "super", "switch", "synchronized", + "this", "throw", "throws", "transient", "true", + "try", "typeof", "var", "void", "volatile", + "while", "with", "yield", + "Array", "Date", "eval", "function", "hasOwnProperty", + "Infinity", "isFinite", "isNaN", "isPrototypeOf", + "Math", "NaN", "Number", "Object", + "prototype", "String", "toString", "undefined", "valueOf") ); languageSpecificPrimitives = new HashSet( - Arrays.asList( - "String", - "boolean", - "Boolean", - "Double", - "Integer", - "Long", - "Float", - "Object", - "byte[]") + Arrays.asList("String", "Boolean", "Integer", "Number", "Array", "Object", "Date", "File") ); - instantiationTypes.put("array", "Array"); - instantiationTypes.put("map", "HashMap"); + defaultIncludes = new HashSet(languageSpecificPrimitives); - cliOptions.add(new CliOption(CodegenConstants.SOURCE_FOLDER, CodegenConstants.SOURCE_FOLDER_DESC)); + cliOptions.add(new CliOption(CodegenConstants.SOURCE_FOLDER, CodegenConstants.SOURCE_FOLDER_DESC).defaultValue("src")); cliOptions.add(new CliOption(CodegenConstants.LOCAL_VARIABLE_PREFIX, CodegenConstants.LOCAL_VARIABLE_PREFIX_DESC)); cliOptions.add(new CliOption(PROJECT_NAME, "name of the project (Default: generated from info.title or \"swagger-js-client\")")); + cliOptions.add(new CliOption(MODULE_NAME, + "module name for AMD, Node or globals (Default: generated from )")); cliOptions.add(new CliOption(PROJECT_DESCRIPTION, - "description of the project (Default: using info.description or \"Client library of \")")); + "description of the project (Default: using info.description or \"Client library of \")")); cliOptions.add(new CliOption(PROJECT_VERSION, "version of the project (Default: using info.version or \"1.0.0\")")); cliOptions.add(new CliOption(PROJECT_LICENSE_NAME, @@ -111,7 +116,25 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo @Override public void processOpts() { super.processOpts(); + + typeMapping = new HashMap(); typeMapping.put("array", "Array"); + typeMapping.put("List", "Array"); + typeMapping.put("map", "Object"); + typeMapping.put("object", "Object"); + typeMapping.put("boolean", "Boolean"); + typeMapping.put("char", "String"); + typeMapping.put("string", "String"); + typeMapping.put("short", "Integer"); + typeMapping.put("int", "Integer"); + typeMapping.put("integer", "Integer"); + typeMapping.put("long", "Integer"); + typeMapping.put("float", "Number"); + typeMapping.put("double", "Number"); + typeMapping.put("number", "Number"); + typeMapping.put("DateTime", "Date"); + + importMapping.clear(); } @Override @@ -121,12 +144,21 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo if (additionalProperties.containsKey(PROJECT_NAME)) { projectName = ((String) additionalProperties.get(PROJECT_NAME)); } + if (additionalProperties.containsKey(MODULE_NAME)) { + moduleName = ((String) additionalProperties.get(MODULE_NAME)); + } if (additionalProperties.containsKey(PROJECT_DESCRIPTION)) { projectDescription = ((String) additionalProperties.get(PROJECT_DESCRIPTION)); } if (additionalProperties.containsKey(PROJECT_VERSION)) { projectVersion = ((String) additionalProperties.get(PROJECT_VERSION)); } + if (additionalProperties.containsKey(CodegenConstants.LOCAL_VARIABLE_PREFIX)) { + localVariablePrefix = (String) additionalProperties.get(CodegenConstants.LOCAL_VARIABLE_PREFIX); + } + if (additionalProperties.containsKey(CodegenConstants.SOURCE_FOLDER)) { + sourceFolder = (String) additionalProperties.get(CodegenConstants.SOURCE_FOLDER); + } if (swagger.getInfo() != null) { Info info = swagger.getInfo(); @@ -154,6 +186,9 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo if (projectName == null) { projectName = "swagger-js-client"; } + if (moduleName == null) { + moduleName = camelize(underscore(projectName)); + } if (projectVersion == null) { projectVersion = "1.0.0"; } @@ -162,8 +197,14 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo } additionalProperties.put(PROJECT_NAME, projectName); + additionalProperties.put(MODULE_NAME, moduleName); additionalProperties.put(PROJECT_DESCRIPTION, escapeText(projectDescription)); additionalProperties.put(PROJECT_VERSION, projectVersion); + additionalProperties.put(CodegenConstants.LOCAL_VARIABLE_PREFIX, localVariablePrefix); + additionalProperties.put(CodegenConstants.SOURCE_FOLDER, sourceFolder); + + supportingFiles.add(new SupportingFile("package.mustache", "", "package.json")); + supportingFiles.add(new SupportingFile("index.mustache", sourceFolder, "index.js")); } @Override @@ -233,6 +274,16 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo return toModelName(name); } + @Override + public String toModelImport(String name) { + return name; + } + + @Override + public String toApiImport(String name) { + return name; + } + @Override public String getTypeDeclaration(Property p) { if (p instanceof ArrayProperty) { @@ -263,8 +314,8 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo // added for Javascript } else if (p instanceof RefProperty) { - RefProperty rp = (RefProperty)p; - return "new " +rp.getSimpleRef() + "()"; + RefProperty rp = (RefProperty)p; + return "new " +rp.getSimpleRef() + "()"; } return super.toDefaultValue(p); @@ -283,8 +334,8 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo // added for Javascript } else if (p instanceof RefProperty) { - RefProperty rp = (RefProperty)p; - return ".constructFromObject(data." + name + ");"; + RefProperty rp = (RefProperty)p; + return ".constructFromObject(data." + name + ");"; } return super.toDefaultValueWithParam(name, p); @@ -297,7 +348,7 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo String type = null; if (typeMapping.containsKey(swaggerType)) { type = typeMapping.get(swaggerType); - if (languageSpecificPrimitives.contains(type) || type.indexOf(".") >= 0) { + if (!needToImport(type)) { return type; } } else { @@ -408,7 +459,8 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo } protected boolean needToImport(String type) { - return super.needToImport(type) && type.indexOf(".") < 0; + return !defaultIncludes.contains(type) + && !languageSpecificPrimitives.contains(type); } private String findCommonPrefixOfVars(List vars) { @@ -475,14 +527,6 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo return codegenModel; } - public void setSourceFolder(String sourceFolder) { - this.sourceFolder = sourceFolder; - } - - public void setLocalVariablePrefix(String localVariablePrefix) { - this.localVariablePrefix = localVariablePrefix; - } - private String sanitizePackageName(String packageName) { packageName = packageName.trim(); packageName = packageName.replaceAll("[^a-zA-Z0-9_\\.]", "_"); diff --git a/modules/swagger-codegen/src/main/resources/Javascript/api.mustache b/modules/swagger-codegen/src/main/resources/Javascript/api.mustache index dd115aaa45c1..cce87ee2f7be 100644 --- a/modules/swagger-codegen/src/main/resources/Javascript/api.mustache +++ b/modules/swagger-codegen/src/main/resources/Javascript/api.mustache @@ -1,6 +1,14 @@ -//export module +// require files in Node.js environment +{{#imports}} +var {{import}};{{/imports}} +if (typeof module === 'object' && module.exports) { + {{#imports}} + {{import}} = require('./{{import}}.js');{{/imports}} +} + +// export module for AMD if ( typeof define === "function" && define.amd ) { - define(['jquery'], function($) { + define(['jquery'{{#imports}}, '{{import}}'{{/imports}}], function(${{#imports}}, {{import}}{{/imports}}) { return {{classname}}; }); } @@ -124,3 +132,8 @@ var {{classname}} = function {{classname}}() { return queryString; } } + +// export module for Node.js +if (typeof module === 'object' && module.exports) { + module.exports = {{classname}}; +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/Javascript/index.mustache b/modules/swagger-codegen/src/main/resources/Javascript/index.mustache new file mode 100644 index 000000000000..a0207a6cc916 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Javascript/index.mustache @@ -0,0 +1,10 @@ +if (typeof module === 'object' && module.exports) { + var {{moduleName}} = {}; + {{#models}} + {{moduleName}}.{{importPath}} = require('./model/{{importPath}}.js'); + {{/models}} + {{#apiInfo}}{{#apis}} + {{moduleName}}.{{importPath}} = require('./api/{{importPath}}.js'); + {{/apis}}{{/apiInfo}} + module.exports = {{moduleName}}; +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/Javascript/model.mustache b/modules/swagger-codegen/src/main/resources/Javascript/model.mustache index acf0bcffc195..8b021a3badd3 100644 --- a/modules/swagger-codegen/src/main/resources/Javascript/model.mustache +++ b/modules/swagger-codegen/src/main/resources/Javascript/model.mustache @@ -1,10 +1,18 @@ +// require files in Node.js environment +{{#imports}} +var {{import}};{{/imports}} +if (typeof module === 'object' && module.exports) { + {{#imports}} + {{import}} = require('./{{import}}.js');{{/imports}} +} + {{#models}}{{#model}} {{#vars}}{{#isEnum}}{{>enumClass}}{{/isEnum}}{{#items.isEnum}}{{#items}} {{>enumClass}}{{/items}}*/{{/items.isEnum}}{{/vars}} //export module -if ( typeof define === "function" && define.amd ) { - define('{{classname}}', ['jquery'{{#vars}}{{^isPrimitiveType}}{{^-last}}, {{/-last}}'{{datatypeWithEnum}}'{{/isPrimitiveType}}{{/vars}}], +if ( typeof define === "function" && define.amd ) { + define('{{classname}}', ['jquery'{{#vars}}{{^isPrimitiveType}}{{^-last}}, {{/-last}}'{{datatypeWithEnum}}'{{/isPrimitiveType}}{{/vars}}], function(${{#vars}}{{^isPrimitiveType}}{{^-last}}, {{/-last}}{{datatypeWithEnum}}{{/isPrimitiveType}}{{/vars}}) { return {{classname}}; }); @@ -56,5 +64,9 @@ var {{classname}} = function {{classname}}({{#mandatory}}{{this}}{{^-last}}, {{/ return JSON.stringify(self); } } + +if (typeof module === 'object' && module.exports) { + module.exports = {{classname}}; +} {{/model}} {{/models}} diff --git a/modules/swagger-codegen/src/main/resources/Javascript/package.mustache b/modules/swagger-codegen/src/main/resources/Javascript/package.mustache index 7c9d45a3e6d2..d39136cafdd6 100644 --- a/modules/swagger-codegen/src/main/resources/Javascript/package.mustache +++ b/modules/swagger-codegen/src/main/resources/Javascript/package.mustache @@ -3,7 +3,7 @@ "version": "{{{projectVersion}}}", "description": "{{{projectDescription}}}",{{#projectLicenseName}} "license": "{{{projectLicenseName}}}",{{/projectLicenseName}} - "main": "index.js", + "main": "{{sourceFolder}}/index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, diff --git a/samples/client/petstore/javascript/package.json b/samples/client/petstore/javascript/package.json new file mode 100644 index 000000000000..926778d30156 --- /dev/null +++ b/samples/client/petstore/javascript/package.json @@ -0,0 +1,13 @@ +{ + "name": "swagger-petstore", + "version": "1.0.0", + "description": "This is a sample server Petstore server. You can find out more about Swagger at http://swagger.io or on irc.freenode.net, #swagger. For this sample, you can use the api key \"special-key\" to test the authorization filters", + "license": "Apache 2.0", + "main": "src/index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "dependencies": { + "jquery": "^2.1.4" + } +} diff --git a/samples/client/petstore/javascript/src/scripts/rest/api/PetApi.js b/samples/client/petstore/javascript/src/api/PetApi.js similarity index 96% rename from samples/client/petstore/javascript/src/scripts/rest/api/PetApi.js rename to samples/client/petstore/javascript/src/api/PetApi.js index 5b4f65234137..58ee6a1c9f7d 100644 --- a/samples/client/petstore/javascript/src/scripts/rest/api/PetApi.js +++ b/samples/client/petstore/javascript/src/api/PetApi.js @@ -1,6 +1,13 @@ -//export module +// require files in Node.js environment +var Pet; +if (typeof module === 'object' && module.exports) { + + Pet = require('./Pet.js'); +} + +// export module for AMD if ( typeof define === "function" && define.amd ) { - define(['jquery'], function($) { + define(['jquery', 'Pet'], function($, Pet) { return PetApi; }); } @@ -243,7 +250,7 @@ var PetApi = function PetApi() { /** * Find pet by ID * Returns a pet when ID < 10. ID > 10 or nonintegers will simulate API error conditions - * @param {Long} petId ID of pet that needs to be fetched + * @param {Integer} petId ID of pet that needs to be fetched * @param {function} callback the callback function * @return Pet */ @@ -379,7 +386,7 @@ var PetApi = function PetApi() { /** * Deletes a pet * - * @param {Long} petId Pet id to delete + * @param {Integer} petId Pet id to delete * @param {String} apiKey * @param {function} callback the callback function * @return void @@ -437,7 +444,7 @@ var PetApi = function PetApi() { /** * uploads an image * - * @param {Long} petId ID of pet to update + * @param {Integer} petId ID of pet to update * @param {String} additionalMetadata Additional data to pass to server * @param {File} file file to upload * @param {function} callback the callback function @@ -522,3 +529,8 @@ var PetApi = function PetApi() { return queryString; } } + +// export module for Node.js +if (typeof module === 'object' && module.exports) { + module.exports = PetApi; +} \ No newline at end of file diff --git a/samples/client/petstore/javascript/src/scripts/rest/api/StoreApi.js b/samples/client/petstore/javascript/src/api/StoreApi.js similarity index 93% rename from samples/client/petstore/javascript/src/scripts/rest/api/StoreApi.js rename to samples/client/petstore/javascript/src/api/StoreApi.js index e27494c7924d..4cc55ae6cc15 100644 --- a/samples/client/petstore/javascript/src/scripts/rest/api/StoreApi.js +++ b/samples/client/petstore/javascript/src/api/StoreApi.js @@ -1,6 +1,13 @@ -//export module +// require files in Node.js environment +var Order; +if (typeof module === 'object' && module.exports) { + + Order = require('./Order.js'); +} + +// export module for AMD if ( typeof define === "function" && define.amd ) { - define(['jquery'], function($) { + define(['jquery', 'Order'], function($, Order) { return StoreApi; }); } @@ -12,7 +19,7 @@ var StoreApi = function StoreApi() { * Returns pet inventories by status * Returns a map of status codes to quantities * @param {function} callback the callback function - * @return Map + * @return Object */ self.getInventory = function(callback) { @@ -47,7 +54,7 @@ var StoreApi = function StoreApi() { - //TypeRef returnType = new TypeRef>() {}; + //TypeRef returnType = new TypeRef>() {}; //return apiClient.invokeAPI(path, "GET", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, returnType); var options = {type: "GET", async: true, contentType: "application/json", dataType: "json", data: postBody}; @@ -59,11 +66,10 @@ var StoreApi = function StoreApi() { request.done(function(response, textStatus, jqXHR){ /** - * @returns Map + * @returns Object */ + var myResponse = response; - var myResponse = new Map(); - myResponse.constructFromObject(response); callback(myResponse, textStatus, jqXHR); }); @@ -298,3 +304,8 @@ var StoreApi = function StoreApi() { return queryString; } } + +// export module for Node.js +if (typeof module === 'object' && module.exports) { + module.exports = StoreApi; +} \ No newline at end of file diff --git a/samples/client/petstore/javascript/src/scripts/rest/api/UserApi.js b/samples/client/petstore/javascript/src/api/UserApi.js similarity index 97% rename from samples/client/petstore/javascript/src/scripts/rest/api/UserApi.js rename to samples/client/petstore/javascript/src/api/UserApi.js index ecd9707fa91e..49883023ae71 100644 --- a/samples/client/petstore/javascript/src/scripts/rest/api/UserApi.js +++ b/samples/client/petstore/javascript/src/api/UserApi.js @@ -1,6 +1,13 @@ -//export module +// require files in Node.js environment +var User; +if (typeof module === 'object' && module.exports) { + + User = require('./User.js'); +} + +// export module for AMD if ( typeof define === "function" && define.amd ) { - define(['jquery'], function($) { + define(['jquery', 'User'], function($, User) { return UserApi; }); } @@ -479,3 +486,8 @@ var UserApi = function UserApi() { return queryString; } } + +// export module for Node.js +if (typeof module === 'object' && module.exports) { + module.exports = UserApi; +} \ No newline at end of file diff --git a/samples/client/petstore/javascript/src/index.js b/samples/client/petstore/javascript/src/index.js new file mode 100644 index 000000000000..f34b7e01432a --- /dev/null +++ b/samples/client/petstore/javascript/src/index.js @@ -0,0 +1,22 @@ +if (typeof module === 'object' && module.exports) { + var SwaggerPetstore = {}; + + SwaggerPetstore.User = require('./model/User.js'); + + SwaggerPetstore.Category = require('./model/Category.js'); + + SwaggerPetstore.Pet = require('./model/Pet.js'); + + SwaggerPetstore.Tag = require('./model/Tag.js'); + + SwaggerPetstore.Order = require('./model/Order.js'); + + + SwaggerPetstore.User = require('./api/User.js'); + + SwaggerPetstore.Store = require('./api/Store.js'); + + SwaggerPetstore.Pet = require('./api/Pet.js'); + + module.exports = SwaggerPetstore; +} \ No newline at end of file diff --git a/samples/client/petstore/javascript/src/scripts/rest/model/Category.js b/samples/client/petstore/javascript/src/model/Category.js similarity index 69% rename from samples/client/petstore/javascript/src/scripts/rest/model/Category.js rename to samples/client/petstore/javascript/src/model/Category.js index aec80bf36355..a87f91354a81 100644 --- a/samples/client/petstore/javascript/src/scripts/rest/model/Category.js +++ b/samples/client/petstore/javascript/src/model/Category.js @@ -1,9 +1,15 @@ +// require files in Node.js environment + +if (typeof module === 'object' && module.exports) { + +} + //export module -if ( typeof define === "function" && define.amd ) { - define('Category', ['jquery'], +if ( typeof define === "function" && define.amd ) { + define('Category', ['jquery'], function($) { return Category; }); @@ -14,7 +20,7 @@ var Category = function Category() { var self = this; /** - * datatype: Long + * datatype: Integer **/ self.id = null; @@ -34,14 +40,14 @@ var Category = function Category() { /** - * @return {Long} + * @return {Integer} **/ self.getId = function() { return self.id; } /** - * @param {Long} id + * @param {Integer} id **/ self.setId = function (id) { self.id = id; @@ -66,3 +72,7 @@ var Category = function Category() { return JSON.stringify(self); } } + +if (typeof module === 'object' && module.exports) { + module.exports = Category; +} diff --git a/samples/client/petstore/javascript/src/scripts/rest/model/Order.js b/samples/client/petstore/javascript/src/model/Order.js similarity index 85% rename from samples/client/petstore/javascript/src/scripts/rest/model/Order.js rename to samples/client/petstore/javascript/src/model/Order.js index 73618cef8889..61120e577d6b 100644 --- a/samples/client/petstore/javascript/src/scripts/rest/model/Order.js +++ b/samples/client/petstore/javascript/src/model/Order.js @@ -1,3 +1,9 @@ +// require files in Node.js environment + +if (typeof module === 'object' && module.exports) { + +} + //export module @@ -30,9 +36,9 @@ var StatusEnum = function StatusEnum() { //export module -if ( typeof define === "function" && define.amd ) { - define('Order', ['jquery', 'Date'], - function($, Date) { +if ( typeof define === "function" && define.amd ) { + define('Order', ['jquery'], + function($) { return Order; }); } @@ -42,12 +48,12 @@ var Order = function Order() { var self = this; /** - * datatype: Long + * datatype: Integer **/ self.id = null; /** - * datatype: Long + * datatype: Integer **/ self.petId = null; @@ -91,28 +97,28 @@ var Order = function Order() { /** - * @return {Long} + * @return {Integer} **/ self.getId = function() { return self.id; } /** - * @param {Long} id + * @param {Integer} id **/ self.setId = function (id) { self.id = id; } /** - * @return {Long} + * @return {Integer} **/ self.getPetId = function() { return self.petId; } /** - * @param {Long} petId + * @param {Integer} petId **/ self.setPetId = function (petId) { self.petId = petId; @@ -181,3 +187,7 @@ var Order = function Order() { return JSON.stringify(self); } } + +if (typeof module === 'object' && module.exports) { + module.exports = Order; +} diff --git a/samples/client/petstore/javascript/src/scripts/rest/model/Pet.js b/samples/client/petstore/javascript/src/model/Pet.js similarity index 85% rename from samples/client/petstore/javascript/src/scripts/rest/model/Pet.js rename to samples/client/petstore/javascript/src/model/Pet.js index 259857334502..7a25a1d5fdd6 100644 --- a/samples/client/petstore/javascript/src/scripts/rest/model/Pet.js +++ b/samples/client/petstore/javascript/src/model/Pet.js @@ -1,3 +1,11 @@ +// require files in Node.js environment +var Category;var Tag; +if (typeof module === 'object' && module.exports) { + + Category = require('./Category.js'); + Tag = require('./Tag.js'); +} + //export module @@ -30,8 +38,8 @@ var StatusEnum = function StatusEnum() { //export module -if ( typeof define === "function" && define.amd ) { - define('Pet', ['jquery', 'Category', 'Array'], +if ( typeof define === "function" && define.amd ) { + define('Pet', ['jquery', 'Category', 'Array'], function($, Category, Array) { return Pet; }); @@ -42,7 +50,7 @@ var Pet = function Pet(photoUrls, name) { var self = this; /** - * datatype: Long + * datatype: Integer **/ self.id = null; @@ -93,14 +101,14 @@ var Pet = function Pet(photoUrls, name) { /** - * @return {Long} + * @return {Integer} **/ self.getId = function() { return self.id; } /** - * @param {Long} id + * @param {Integer} id **/ self.setId = function (id) { self.id = id; @@ -183,3 +191,7 @@ var Pet = function Pet(photoUrls, name) { return JSON.stringify(self); } } + +if (typeof module === 'object' && module.exports) { + module.exports = Pet; +} diff --git a/samples/client/petstore/javascript/src/scripts/rest/model/Tag.js b/samples/client/petstore/javascript/src/model/Tag.js similarity index 69% rename from samples/client/petstore/javascript/src/scripts/rest/model/Tag.js rename to samples/client/petstore/javascript/src/model/Tag.js index 07994ec3dc93..4801da71e41d 100644 --- a/samples/client/petstore/javascript/src/scripts/rest/model/Tag.js +++ b/samples/client/petstore/javascript/src/model/Tag.js @@ -1,9 +1,15 @@ +// require files in Node.js environment + +if (typeof module === 'object' && module.exports) { + +} + //export module -if ( typeof define === "function" && define.amd ) { - define('Tag', ['jquery'], +if ( typeof define === "function" && define.amd ) { + define('Tag', ['jquery'], function($) { return Tag; }); @@ -14,7 +20,7 @@ var Tag = function Tag() { var self = this; /** - * datatype: Long + * datatype: Integer **/ self.id = null; @@ -34,14 +40,14 @@ var Tag = function Tag() { /** - * @return {Long} + * @return {Integer} **/ self.getId = function() { return self.id; } /** - * @param {Long} id + * @param {Integer} id **/ self.setId = function (id) { self.id = id; @@ -66,3 +72,7 @@ var Tag = function Tag() { return JSON.stringify(self); } } + +if (typeof module === 'object' && module.exports) { + module.exports = Tag; +} diff --git a/samples/client/petstore/javascript/src/scripts/rest/model/User.js b/samples/client/petstore/javascript/src/model/User.js similarity index 89% rename from samples/client/petstore/javascript/src/scripts/rest/model/User.js rename to samples/client/petstore/javascript/src/model/User.js index 19afab44ee68..6d32676a9213 100644 --- a/samples/client/petstore/javascript/src/scripts/rest/model/User.js +++ b/samples/client/petstore/javascript/src/model/User.js @@ -1,9 +1,15 @@ +// require files in Node.js environment + +if (typeof module === 'object' && module.exports) { + +} + //export module -if ( typeof define === "function" && define.amd ) { - define('User', ['jquery'], +if ( typeof define === "function" && define.amd ) { + define('User', ['jquery'], function($) { return User; }); @@ -14,7 +20,7 @@ var User = function User() { var self = this; /** - * datatype: Long + * datatype: Integer **/ self.id = null; @@ -77,14 +83,14 @@ var User = function User() { /** - * @return {Long} + * @return {Integer} **/ self.getId = function() { return self.id; } /** - * @param {Long} id + * @param {Integer} id **/ self.setId = function (id) { self.id = id; @@ -195,3 +201,7 @@ var User = function User() { return JSON.stringify(self); } } + +if (typeof module === 'object' && module.exports) { + module.exports = User; +} From cc408a0dd7164a61529653585a5c251d4f44317a Mon Sep 17 00:00:00 2001 From: xhh Date: Thu, 17 Dec 2015 00:32:50 +0800 Subject: [PATCH 63/71] Add unit tests to Javascript Petstore sample --- .../languages/JavascriptClientCodegen.java | 2 +- .../main/resources/Javascript/api.mustache | 7 +++--- .../resources/Javascript/package.mustache | 7 +++++- .../client/petstore/javascript/package.json | 7 +++++- .../petstore/javascript/src/api/PetApi.js | 6 ++--- .../petstore/javascript/src/api/StoreApi.js | 6 ++--- .../petstore/javascript/src/api/UserApi.js | 6 ++--- .../client/petstore/javascript/src/index.js | 6 ++--- .../client/petstore/javascript/test/test.js | 22 +++++++++++++++++++ 9 files changed, 50 insertions(+), 19 deletions(-) create mode 100644 samples/client/petstore/javascript/test/test.js diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavascriptClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavascriptClientCodegen.java index 62bc42bf21d2..55b847668c0b 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavascriptClientCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavascriptClientCodegen.java @@ -281,7 +281,7 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo @Override public String toApiImport(String name) { - return name; + return toApiName(name); } @Override diff --git a/modules/swagger-codegen/src/main/resources/Javascript/api.mustache b/modules/swagger-codegen/src/main/resources/Javascript/api.mustache index cce87ee2f7be..2a0c74ce5604 100644 --- a/modules/swagger-codegen/src/main/resources/Javascript/api.mustache +++ b/modules/swagger-codegen/src/main/resources/Javascript/api.mustache @@ -1,9 +1,8 @@ // require files in Node.js environment -{{#imports}} -var {{import}};{{/imports}} +var ${{#imports}}, {{import}}{{/imports}}; if (typeof module === 'object' && module.exports) { - {{#imports}} - {{import}} = require('./{{import}}.js');{{/imports}} + $ = require('jquery');{{#imports}} + {{import}} = require('../model/{{import}}.js');{{/imports}} } // export module for AMD diff --git a/modules/swagger-codegen/src/main/resources/Javascript/package.mustache b/modules/swagger-codegen/src/main/resources/Javascript/package.mustache index d39136cafdd6..85603bd364b6 100644 --- a/modules/swagger-codegen/src/main/resources/Javascript/package.mustache +++ b/modules/swagger-codegen/src/main/resources/Javascript/package.mustache @@ -5,9 +5,14 @@ "license": "{{{projectLicenseName}}}",{{/projectLicenseName}} "main": "{{sourceFolder}}/index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "./node_modules/mocha/bin/mocha" }, "dependencies": { "jquery": "^2.1.4" + }, + "devDependencies": { + "mocha": "^2.3.4", + "mockrequire": "0.0.5", + "najax": "0.3.1" } } diff --git a/samples/client/petstore/javascript/package.json b/samples/client/petstore/javascript/package.json index 926778d30156..c5f1afde698c 100644 --- a/samples/client/petstore/javascript/package.json +++ b/samples/client/petstore/javascript/package.json @@ -5,9 +5,14 @@ "license": "Apache 2.0", "main": "src/index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "./node_modules/mocha/bin/mocha" }, "dependencies": { "jquery": "^2.1.4" + }, + "devDependencies": { + "mocha": "^2.3.4", + "mockrequire": "0.0.5", + "najax": "0.3.1" } } diff --git a/samples/client/petstore/javascript/src/api/PetApi.js b/samples/client/petstore/javascript/src/api/PetApi.js index 58ee6a1c9f7d..d9e10256b1c5 100644 --- a/samples/client/petstore/javascript/src/api/PetApi.js +++ b/samples/client/petstore/javascript/src/api/PetApi.js @@ -1,8 +1,8 @@ // require files in Node.js environment -var Pet; +var $, Pet; if (typeof module === 'object' && module.exports) { - - Pet = require('./Pet.js'); + $ = require('jquery'); + Pet = require('../model/Pet.js'); } // export module for AMD diff --git a/samples/client/petstore/javascript/src/api/StoreApi.js b/samples/client/petstore/javascript/src/api/StoreApi.js index 4cc55ae6cc15..7a20d8841a36 100644 --- a/samples/client/petstore/javascript/src/api/StoreApi.js +++ b/samples/client/petstore/javascript/src/api/StoreApi.js @@ -1,8 +1,8 @@ // require files in Node.js environment -var Order; +var $, Order; if (typeof module === 'object' && module.exports) { - - Order = require('./Order.js'); + $ = require('jquery'); + Order = require('../model/Order.js'); } // export module for AMD diff --git a/samples/client/petstore/javascript/src/api/UserApi.js b/samples/client/petstore/javascript/src/api/UserApi.js index 49883023ae71..72dc3f3d198e 100644 --- a/samples/client/petstore/javascript/src/api/UserApi.js +++ b/samples/client/petstore/javascript/src/api/UserApi.js @@ -1,8 +1,8 @@ // require files in Node.js environment -var User; +var $, User; if (typeof module === 'object' && module.exports) { - - User = require('./User.js'); + $ = require('jquery'); + User = require('../model/User.js'); } // export module for AMD diff --git a/samples/client/petstore/javascript/src/index.js b/samples/client/petstore/javascript/src/index.js index f34b7e01432a..b772f6024dca 100644 --- a/samples/client/petstore/javascript/src/index.js +++ b/samples/client/petstore/javascript/src/index.js @@ -12,11 +12,11 @@ if (typeof module === 'object' && module.exports) { SwaggerPetstore.Order = require('./model/Order.js'); - SwaggerPetstore.User = require('./api/User.js'); + SwaggerPetstore.UserApi = require('./api/UserApi.js'); - SwaggerPetstore.Store = require('./api/Store.js'); + SwaggerPetstore.StoreApi = require('./api/StoreApi.js'); - SwaggerPetstore.Pet = require('./api/Pet.js'); + SwaggerPetstore.PetApi = require('./api/PetApi.js'); module.exports = SwaggerPetstore; } \ No newline at end of file diff --git a/samples/client/petstore/javascript/test/test.js b/samples/client/petstore/javascript/test/test.js new file mode 100644 index 000000000000..c7d84917f8a2 --- /dev/null +++ b/samples/client/petstore/javascript/test/test.js @@ -0,0 +1,22 @@ +var assert = require('assert'); +var mockrequire = require('mockrequire'); +var najax = require('najax'); + +var PetApi = mockrequire('../src/api/PetApi', { + 'jquery': { + 'ajax': najax + } +}); + +describe('PetApi', function() { + describe('#getPetById', function () { + it('should work', function (done) { + var api = new PetApi(); + api.getPetById(1, function(pet, textStatus, jqXHR) { + assert.equal('success', textStatus); + assert.equal(1, pet.id); + done(); + }); + }); + }); +}); From 5a1c6e6c17bcbfc72abad3856401cdbb17dfde9b Mon Sep 17 00:00:00 2001 From: Tomek Cejner Date: Wed, 16 Dec 2015 21:55:31 +0100 Subject: [PATCH 64/71] Updated samples, and cartfile --- .../swagger-codegen/src/main/resources/swift/Cartfile.mustache | 2 +- samples/client/petstore/swift/Cartfile | 2 +- samples/client/petstore/swift/PetstoreClient.podspec | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/swagger-codegen/src/main/resources/swift/Cartfile.mustache b/modules/swagger-codegen/src/main/resources/swift/Cartfile.mustache index c27fd0c14d12..a0906ba59692 100644 --- a/modules/swagger-codegen/src/main/resources/swift/Cartfile.mustache +++ b/modules/swagger-codegen/src/main/resources/swift/Cartfile.mustache @@ -1,2 +1,2 @@ -github "Alamofire/Alamofire" >= 3.0.0{{#usePromiseKit}} +github "Alamofire/Alamofire" >= 3.1.0{{#usePromiseKit}} github "mxcl/PromiseKit" >=1.5.3{{/usePromiseKit}} diff --git a/samples/client/petstore/swift/Cartfile b/samples/client/petstore/swift/Cartfile index 745e00376a80..5e4bd352eefc 100644 --- a/samples/client/petstore/swift/Cartfile +++ b/samples/client/petstore/swift/Cartfile @@ -1,2 +1,2 @@ -github "Alamofire/Alamofire" >= 3.0.0 +github "Alamofire/Alamofire" >= 3.1.0 github "mxcl/PromiseKit" >=1.5.3 diff --git a/samples/client/petstore/swift/PetstoreClient.podspec b/samples/client/petstore/swift/PetstoreClient.podspec index 3caf12083de0..ed41db4bfb13 100644 --- a/samples/client/petstore/swift/PetstoreClient.podspec +++ b/samples/client/petstore/swift/PetstoreClient.podspec @@ -7,5 +7,5 @@ Pod::Spec.new do |s| s.license = 'Apache License, Version 2.0' s.source_files = 'PetstoreClient/Classes/Swaggers/**/*.swift' s.dependency 'PromiseKit', '~> 2.1' - s.dependency 'Alamofire', '~> 3.0.0' + s.dependency 'Alamofire', '~> 3.1.0' end From 146b4a481366321304d6197c85cd73c85877f020 Mon Sep 17 00:00:00 2001 From: xhh Date: Thu, 17 Dec 2015 17:59:57 +0800 Subject: [PATCH 65/71] Use a more real jquery mocking in test --- .../main/resources/Javascript/package.mustache | 9 +++++---- samples/client/petstore/javascript/package.json | 9 +++++---- .../client/petstore/javascript/test/mocha.opts | 1 + samples/client/petstore/javascript/test/test.js | 15 +++++++++++---- 4 files changed, 22 insertions(+), 12 deletions(-) create mode 100644 samples/client/petstore/javascript/test/mocha.opts diff --git a/modules/swagger-codegen/src/main/resources/Javascript/package.mustache b/modules/swagger-codegen/src/main/resources/Javascript/package.mustache index 85603bd364b6..e86b1a17aee4 100644 --- a/modules/swagger-codegen/src/main/resources/Javascript/package.mustache +++ b/modules/swagger-codegen/src/main/resources/Javascript/package.mustache @@ -8,11 +8,12 @@ "test": "./node_modules/mocha/bin/mocha" }, "dependencies": { - "jquery": "^2.1.4" + "jquery": "~2.1.4" }, "devDependencies": { - "mocha": "^2.3.4", - "mockrequire": "0.0.5", - "najax": "0.3.1" + "mocha": "~2.3.4", + "mockrequire": "~0.0.5", + "domino": "~1.0.20", + "xmlhttprequest": "~1.8.0" } } diff --git a/samples/client/petstore/javascript/package.json b/samples/client/petstore/javascript/package.json index c5f1afde698c..a7bc83e4ae2c 100644 --- a/samples/client/petstore/javascript/package.json +++ b/samples/client/petstore/javascript/package.json @@ -8,11 +8,12 @@ "test": "./node_modules/mocha/bin/mocha" }, "dependencies": { - "jquery": "^2.1.4" + "jquery": "~2.1.4" }, "devDependencies": { - "mocha": "^2.3.4", - "mockrequire": "0.0.5", - "najax": "0.3.1" + "mocha": "~2.3.4", + "mockrequire": "~0.0.5", + "domino": "~1.0.20", + "xmlhttprequest": "~1.8.0" } } diff --git a/samples/client/petstore/javascript/test/mocha.opts b/samples/client/petstore/javascript/test/mocha.opts new file mode 100644 index 000000000000..cf80ee74bca1 --- /dev/null +++ b/samples/client/petstore/javascript/test/mocha.opts @@ -0,0 +1 @@ +--timeout 5000 diff --git a/samples/client/petstore/javascript/test/test.js b/samples/client/petstore/javascript/test/test.js index c7d84917f8a2..8b4f3953e6d4 100644 --- a/samples/client/petstore/javascript/test/test.js +++ b/samples/client/petstore/javascript/test/test.js @@ -1,11 +1,18 @@ var assert = require('assert'); var mockrequire = require('mockrequire'); -var najax = require('najax'); + +var jquery = require('jquery'); +var domino = require('domino'); +var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; +var window = domino.createWindow(); +var $ = jquery(window); +$.support.cors = true; +$.ajaxSettings.xhr = function() { + return new XMLHttpRequest(); +}; var PetApi = mockrequire('../src/api/PetApi', { - 'jquery': { - 'ajax': najax - } + 'jquery': $ }); describe('PetApi', function() { From dcfe40fc444b854b5796260488e4319ca97f2fec Mon Sep 17 00:00:00 2001 From: xhh Date: Thu, 17 Dec 2015 18:51:12 +0800 Subject: [PATCH 66/71] Configure Javascript tests to allow running in browser --- .../resources/Javascript/package.mustache | 1 + .../client/petstore/javascript/package.json | 1 + .../client/petstore/javascript/test/helper.js | 19 +++++++++++ .../petstore/javascript/test/run_tests.html | 33 +++++++++++++++++++ .../client/petstore/javascript/test/test.js | 25 ++++---------- 5 files changed, 61 insertions(+), 18 deletions(-) create mode 100644 samples/client/petstore/javascript/test/helper.js create mode 100644 samples/client/petstore/javascript/test/run_tests.html diff --git a/modules/swagger-codegen/src/main/resources/Javascript/package.mustache b/modules/swagger-codegen/src/main/resources/Javascript/package.mustache index e86b1a17aee4..53bbed30be93 100644 --- a/modules/swagger-codegen/src/main/resources/Javascript/package.mustache +++ b/modules/swagger-codegen/src/main/resources/Javascript/package.mustache @@ -12,6 +12,7 @@ }, "devDependencies": { "mocha": "~2.3.4", + "expect.js": "~0.3.1", "mockrequire": "~0.0.5", "domino": "~1.0.20", "xmlhttprequest": "~1.8.0" diff --git a/samples/client/petstore/javascript/package.json b/samples/client/petstore/javascript/package.json index a7bc83e4ae2c..156300cf760f 100644 --- a/samples/client/petstore/javascript/package.json +++ b/samples/client/petstore/javascript/package.json @@ -12,6 +12,7 @@ }, "devDependencies": { "mocha": "~2.3.4", + "expect.js": "~0.3.1", "mockrequire": "~0.0.5", "domino": "~1.0.20", "xmlhttprequest": "~1.8.0" diff --git a/samples/client/petstore/javascript/test/helper.js b/samples/client/petstore/javascript/test/helper.js new file mode 100644 index 000000000000..a1b798f325f4 --- /dev/null +++ b/samples/client/petstore/javascript/test/helper.js @@ -0,0 +1,19 @@ +var mockrequire = require('mockrequire'); + +var jquery = require('jquery'); +var domino = require('domino'); +var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; +var window = domino.createWindow(); +var $ = jquery(window); +$.support.cors = true; +$.ajaxSettings.xhr = function() { + return new XMLHttpRequest(); +}; + +var requireWithMocks = function(path) { + return mockrequire(path, { + 'jquery': $ + }); +}; + +exports.requireWithMocks = requireWithMocks; diff --git a/samples/client/petstore/javascript/test/run_tests.html b/samples/client/petstore/javascript/test/run_tests.html new file mode 100644 index 000000000000..9f2d78ad0b86 --- /dev/null +++ b/samples/client/petstore/javascript/test/run_tests.html @@ -0,0 +1,33 @@ + + + + Mocha Tests + + + +
+ + + + + + + + + + + + + + + + diff --git a/samples/client/petstore/javascript/test/test.js b/samples/client/petstore/javascript/test/test.js index 8b4f3953e6d4..3c437d0cd5a5 100644 --- a/samples/client/petstore/javascript/test/test.js +++ b/samples/client/petstore/javascript/test/test.js @@ -1,27 +1,16 @@ -var assert = require('assert'); -var mockrequire = require('mockrequire'); - -var jquery = require('jquery'); -var domino = require('domino'); -var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; -var window = domino.createWindow(); -var $ = jquery(window); -$.support.cors = true; -$.ajaxSettings.xhr = function() { - return new XMLHttpRequest(); -}; - -var PetApi = mockrequire('../src/api/PetApi', { - 'jquery': $ -}); +if (typeof module === 'object' && module.exports) { + var expect = require('expect.js'); + var requireWithMocks = require('./helper.js').requireWithMocks; + var PetApi = requireWithMocks('../src/api/PetApi'); +} describe('PetApi', function() { describe('#getPetById', function () { it('should work', function (done) { var api = new PetApi(); api.getPetById(1, function(pet, textStatus, jqXHR) { - assert.equal('success', textStatus); - assert.equal(1, pet.id); + expect(textStatus).to.be('success'); + expect(pet.id).to.be(1); done(); }); }); From 794783a4bb6c35ac771954d067a74620d2fa5539 Mon Sep 17 00:00:00 2001 From: xhh Date: Thu, 17 Dec 2015 20:05:00 +0800 Subject: [PATCH 67/71] Javascript: bug fixes, clean-ups, tests - Fix the "apiClient.escapeString" issue - Remove unused code in api.mustache - Add test case for creating and getting Pet --- .../main/resources/Javascript/api.mustache | 66 ++-- .../petstore/javascript/src/api/PetApi.js | 309 ++++++++---------- .../petstore/javascript/src/api/StoreApi.js | 179 ++++------ .../petstore/javascript/src/api/UserApi.js | 289 +++++++--------- .../javascript/test/api/PetApiTest.js | 183 +++++++++++ .../client/petstore/javascript/test/helper.js | 6 +- .../petstore/javascript/test/run_tests.html | 14 +- .../client/petstore/javascript/test/test.js | 18 - 8 files changed, 541 insertions(+), 523 deletions(-) create mode 100644 samples/client/petstore/javascript/test/api/PetApiTest.js delete mode 100644 samples/client/petstore/javascript/test/test.js diff --git a/modules/swagger-codegen/src/main/resources/Javascript/api.mustache b/modules/swagger-codegen/src/main/resources/Javascript/api.mustache index 2a0c74ce5604..3da5ff00aa15 100644 --- a/modules/swagger-codegen/src/main/resources/Javascript/api.mustache +++ b/modules/swagger-codegen/src/main/resources/Javascript/api.mustache @@ -14,7 +14,7 @@ if ( typeof define === "function" && define.amd ) { var {{classname}} = function {{classname}}() { var self = this; -{{#operations}} + {{#operations}} {{#operation}} /** * {{summary}} @@ -24,7 +24,6 @@ var {{classname}} = function {{classname}}() { * @return {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}} */ self.{{nickname}} = function({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}{{#hasParams}}, {{/hasParams}}callback) { - var {{localVariablePrefix}}postBody = {{#bodyParam}}{{^isBinary}}JSON.stringify({{paramName}}){{/isBinary}}{{#isBinary}}null{{/isBinary}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}}; var {{localVariablePrefix}}postBinaryBody = {{#bodyParam}}{{#isBinary}}{{paramName}}{{/isBinary}}{{^isBinary}}null{{/isBinary}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}}; {{#allParams}}{{#required}} @@ -42,8 +41,8 @@ var {{classname}} = function {{classname}}() { basePath = basePath.substring(0, basePath.length-1); } - var {{localVariablePrefix}}path = basePath + replaceAll(replaceAll("{{{path}}}", "\\{format\\}","json"){{#pathParams}} -, "\\{" + "{{baseName}}" + "\\}", {{localVariablePrefix}}apiClient.escapeString({{{paramName}}}.toString()){{/pathParams}}); + var {{localVariablePrefix}}path = basePath + replaceAll(replaceAll("{{{path}}}", "\\{format\\}","json"){{#pathParams}} +, "\\{" + "{{baseName}}" + "\\}", {{localVariablePrefix}}{{{paramName}}}.toString(){{/pathParams}}); var queryParams = {}; var headerParams = {}; @@ -59,52 +58,35 @@ var {{classname}} = function {{classname}}() { {{localVariablePrefix}}formParams.put("{{baseName}}", {{paramName}}); {{/formParams}} - path += createQueryString(queryParams); + path += createQueryString(queryParams); - //if (console) { - //console.log('path: ' + path); - //console.log('queryParams: ' + queryParams); - //} - - {{#isResponseBinary}} - byte[] {{localVariablePrefix}}response = null; - {{localVariablePrefix}}response = {{localVariablePrefix}}apiClient.invokeBinaryAPI({{localVariablePrefix}}path, "{{httpMethod}}", {{localVariablePrefix}}queryParams,{{localVariablePrefix}} postBody, {{localVariablePrefix}}postBinaryBody, {{localVariablePrefix}}headerParams, {{localVariablePrefix}}formParams, {{localVariablePrefix}}accept, {{localVariablePrefix}}contentType, {{localVariablePrefix}}authNames); - return {{localVariablePrefix}}response; - {{/isResponseBinary}} - - {{^isResponseBinary}} - {{#returnType}} - //TypeRef {{localVariablePrefix}}returnType = new TypeRef<{{{returnType}}}>() {}; - //return {{localVariablePrefix}}apiClient.invokeAPI({{localVariablePrefix}}path, "{{httpMethod}}", {{localVariablePrefix}}queryParams, {{localVariablePrefix}}postBody, {{localVariablePrefix}}postBinaryBody, {{localVariablePrefix}}headerParams, {{localVariablePrefix}}formParams, {{localVariablePrefix}}accept, {{localVariablePrefix}}contentType, {{localVariablePrefix}}authNames, {{localVariablePrefix}}returnType); - - var options = {type: "{{httpMethod}}", async: true, contentType: "application/json", dataType: "json", data: postBody}; + var options = {type: "{{httpMethod}}", async: true, contentType: "application/json", dataType: "json", data: postBody}; var request = $.ajax(path, options); //request.fail(function(jqXHR, textStatus, errorThrown){ // errorHandler(jqXHR, textStatus, errorThrown); //}); - request.done(function(response, textStatus, jqXHR){ - /** - * @returns {{{returnType}}} - */ - {{#returnTypeIsPrimitive}} var myResponse = response;{{/returnTypeIsPrimitive}} - {{^returnTypeIsPrimitive}} var myResponse = new {{{returnType}}}(); - myResponse.constructFromObject(response);{{/returnTypeIsPrimitive}} - - callback(myResponse, textStatus, jqXHR); - }); - - {{/returnType}}{{^returnType}} - {{localVariablePrefix}}apiClient.invokeAPI({{localVariablePrefix}}path, "{{httpMethod}}", {{localVariablePrefix}}queryParams, {{localVariablePrefix}}postBody, {{localVariablePrefix}}postBinaryBody, {{localVariablePrefix}}headerParams, {{localVariablePrefix}}formParams, {{localVariablePrefix}}accept, {{localVariablePrefix}}contentType, {{localVariablePrefix}}authNames, null); - {{/returnType}} - {{/isResponseBinary}} - - + request.done(function(response, textStatus, jqXHR){ + {{#returnType}} + /** + * @returns {{{returnType}}} + */ + {{#returnTypeIsPrimitive}}var myResponse = response;{{/returnTypeIsPrimitive}} + {{^returnTypeIsPrimitive}}var myResponse = new {{{returnType}}}(); + myResponse.constructFromObject(response);{{/returnTypeIsPrimitive}} + if (callback) { + callback(myResponse, textStatus, jqXHR); + } + {{/returnType}}{{^returnType}} + if (callback) { + callback(response, textStatus, jqXHR); + } + {{/returnType}} + }); } {{/operation}} - -{{/operations}} + {{/operations}} function replaceAll (haystack, needle, replace) { var result= haystack; @@ -135,4 +117,4 @@ var {{classname}} = function {{classname}}() { // export module for Node.js if (typeof module === 'object' && module.exports) { module.exports = {{classname}}; -} \ No newline at end of file +} diff --git a/samples/client/petstore/javascript/src/api/PetApi.js b/samples/client/petstore/javascript/src/api/PetApi.js index d9e10256b1c5..4f77c603b238 100644 --- a/samples/client/petstore/javascript/src/api/PetApi.js +++ b/samples/client/petstore/javascript/src/api/PetApi.js @@ -15,6 +15,7 @@ if ( typeof define === "function" && define.amd ) { var PetApi = function PetApi() { var self = this; + /** * Update an existing pet * @@ -23,7 +24,6 @@ var PetApi = function PetApi() { * @return void */ self.updatePet = function(body, callback) { - var postBody = JSON.stringify(body); var postBinaryBody = null; @@ -34,7 +34,7 @@ var PetApi = function PetApi() { basePath = basePath.substring(0, basePath.length-1); } - var path = basePath + replaceAll(replaceAll("/pet", "\\{format\\}","json")); + var path = basePath + replaceAll(replaceAll("/pet", "\\{format\\}","json")); var queryParams = {}; var headerParams = {}; @@ -44,22 +44,22 @@ var PetApi = function PetApi() { - path += createQueryString(queryParams); - - //if (console) { - //console.log('path: ' + path); - //console.log('queryParams: ' + queryParams); - //} + path += createQueryString(queryParams); + var options = {type: "PUT", async: true, contentType: "application/json", dataType: "json", data: postBody}; + var request = $.ajax(path, options); + //request.fail(function(jqXHR, textStatus, errorThrown){ + // errorHandler(jqXHR, textStatus, errorThrown); + //}); - - - - apiClient.invokeAPI(path, "PUT", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, null); - - - - + + request.done(function(response, textStatus, jqXHR){ + + if (callback) { + callback(response, textStatus, jqXHR); + } + + }); } /** @@ -70,7 +70,6 @@ var PetApi = function PetApi() { * @return void */ self.addPet = function(body, callback) { - var postBody = JSON.stringify(body); var postBinaryBody = null; @@ -81,7 +80,7 @@ var PetApi = function PetApi() { basePath = basePath.substring(0, basePath.length-1); } - var path = basePath + replaceAll(replaceAll("/pet", "\\{format\\}","json")); + var path = basePath + replaceAll(replaceAll("/pet", "\\{format\\}","json")); var queryParams = {}; var headerParams = {}; @@ -91,22 +90,22 @@ var PetApi = function PetApi() { - path += createQueryString(queryParams); - - //if (console) { - //console.log('path: ' + path); - //console.log('queryParams: ' + queryParams); - //} + path += createQueryString(queryParams); + var options = {type: "POST", async: true, contentType: "application/json", dataType: "json", data: postBody}; + var request = $.ajax(path, options); + //request.fail(function(jqXHR, textStatus, errorThrown){ + // errorHandler(jqXHR, textStatus, errorThrown); + //}); - - - - apiClient.invokeAPI(path, "POST", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, null); - - - - + + request.done(function(response, textStatus, jqXHR){ + + if (callback) { + callback(response, textStatus, jqXHR); + } + + }); } /** @@ -117,7 +116,6 @@ var PetApi = function PetApi() { * @return Array */ self.findPetsByStatus = function(status, callback) { - var postBody = null; var postBinaryBody = null; @@ -128,7 +126,7 @@ var PetApi = function PetApi() { basePath = basePath.substring(0, basePath.length-1); } - var path = basePath + replaceAll(replaceAll("/pet/findByStatus", "\\{format\\}","json")); + var path = basePath + replaceAll(replaceAll("/pet/findByStatus", "\\{format\\}","json")); var queryParams = {}; var headerParams = {}; @@ -140,42 +138,28 @@ var PetApi = function PetApi() { - path += createQueryString(queryParams); + path += createQueryString(queryParams); - //if (console) { - //console.log('path: ' + path); - //console.log('queryParams: ' + queryParams); - //} - - - - - - //TypeRef returnType = new TypeRef() {}; - //return apiClient.invokeAPI(path, "GET", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, returnType); - - var options = {type: "GET", async: true, contentType: "application/json", dataType: "json", data: postBody}; + var options = {type: "GET", async: true, contentType: "application/json", dataType: "json", data: postBody}; var request = $.ajax(path, options); //request.fail(function(jqXHR, textStatus, errorThrown){ // errorHandler(jqXHR, textStatus, errorThrown); //}); - request.done(function(response, textStatus, jqXHR){ - /** - * @returns Array - */ - - var myResponse = new Array(); - myResponse.constructFromObject(response); - - callback(myResponse, textStatus, jqXHR); - }); - - - - - + request.done(function(response, textStatus, jqXHR){ + + /** + * @returns Array + */ + + var myResponse = new Array(); + myResponse.constructFromObject(response); + if (callback) { + callback(myResponse, textStatus, jqXHR); + } + + }); } /** @@ -186,7 +170,6 @@ var PetApi = function PetApi() { * @return Array */ self.findPetsByTags = function(tags, callback) { - var postBody = null; var postBinaryBody = null; @@ -197,7 +180,7 @@ var PetApi = function PetApi() { basePath = basePath.substring(0, basePath.length-1); } - var path = basePath + replaceAll(replaceAll("/pet/findByTags", "\\{format\\}","json")); + var path = basePath + replaceAll(replaceAll("/pet/findByTags", "\\{format\\}","json")); var queryParams = {}; var headerParams = {}; @@ -209,42 +192,28 @@ var PetApi = function PetApi() { - path += createQueryString(queryParams); + path += createQueryString(queryParams); - //if (console) { - //console.log('path: ' + path); - //console.log('queryParams: ' + queryParams); - //} - - - - - - //TypeRef returnType = new TypeRef() {}; - //return apiClient.invokeAPI(path, "GET", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, returnType); - - var options = {type: "GET", async: true, contentType: "application/json", dataType: "json", data: postBody}; + var options = {type: "GET", async: true, contentType: "application/json", dataType: "json", data: postBody}; var request = $.ajax(path, options); //request.fail(function(jqXHR, textStatus, errorThrown){ // errorHandler(jqXHR, textStatus, errorThrown); //}); - request.done(function(response, textStatus, jqXHR){ - /** - * @returns Array - */ - - var myResponse = new Array(); - myResponse.constructFromObject(response); - - callback(myResponse, textStatus, jqXHR); - }); - - - - - + request.done(function(response, textStatus, jqXHR){ + + /** + * @returns Array + */ + + var myResponse = new Array(); + myResponse.constructFromObject(response); + if (callback) { + callback(myResponse, textStatus, jqXHR); + } + + }); } /** @@ -255,7 +224,6 @@ var PetApi = function PetApi() { * @return Pet */ self.getPetById = function(petId, callback) { - var postBody = null; var postBinaryBody = null; @@ -273,8 +241,8 @@ var PetApi = function PetApi() { basePath = basePath.substring(0, basePath.length-1); } - var path = basePath + replaceAll(replaceAll("/pet/{petId}", "\\{format\\}","json") -, "\\{" + "petId" + "\\}", apiClient.escapeString(petId.toString())); + var path = basePath + replaceAll(replaceAll("/pet/{petId}", "\\{format\\}","json") +, "\\{" + "petId" + "\\}", petId.toString()); var queryParams = {}; var headerParams = {}; @@ -284,42 +252,28 @@ var PetApi = function PetApi() { - path += createQueryString(queryParams); + path += createQueryString(queryParams); - //if (console) { - //console.log('path: ' + path); - //console.log('queryParams: ' + queryParams); - //} - - - - - - //TypeRef returnType = new TypeRef() {}; - //return apiClient.invokeAPI(path, "GET", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, returnType); - - var options = {type: "GET", async: true, contentType: "application/json", dataType: "json", data: postBody}; + var options = {type: "GET", async: true, contentType: "application/json", dataType: "json", data: postBody}; var request = $.ajax(path, options); //request.fail(function(jqXHR, textStatus, errorThrown){ // errorHandler(jqXHR, textStatus, errorThrown); //}); - request.done(function(response, textStatus, jqXHR){ - /** - * @returns Pet - */ - - var myResponse = new Pet(); - myResponse.constructFromObject(response); - - callback(myResponse, textStatus, jqXHR); - }); - - - - - + request.done(function(response, textStatus, jqXHR){ + + /** + * @returns Pet + */ + + var myResponse = new Pet(); + myResponse.constructFromObject(response); + if (callback) { + callback(myResponse, textStatus, jqXHR); + } + + }); } /** @@ -332,7 +286,6 @@ var PetApi = function PetApi() { * @return void */ self.updatePetWithForm = function(petId, name, status, callback) { - var postBody = null; var postBinaryBody = null; @@ -350,8 +303,8 @@ var PetApi = function PetApi() { basePath = basePath.substring(0, basePath.length-1); } - var path = basePath + replaceAll(replaceAll("/pet/{petId}", "\\{format\\}","json") -, "\\{" + "petId" + "\\}", apiClient.escapeString(petId.toString())); + var path = basePath + replaceAll(replaceAll("/pet/{petId}", "\\{format\\}","json") +, "\\{" + "petId" + "\\}", petId.toString()); var queryParams = {}; var headerParams = {}; @@ -365,22 +318,22 @@ var PetApi = function PetApi() { formParams.put("status", status); - path += createQueryString(queryParams); - - //if (console) { - //console.log('path: ' + path); - //console.log('queryParams: ' + queryParams); - //} + path += createQueryString(queryParams); + var options = {type: "POST", async: true, contentType: "application/json", dataType: "json", data: postBody}; + var request = $.ajax(path, options); + //request.fail(function(jqXHR, textStatus, errorThrown){ + // errorHandler(jqXHR, textStatus, errorThrown); + //}); - - - - apiClient.invokeAPI(path, "POST", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, null); - - - - + + request.done(function(response, textStatus, jqXHR){ + + if (callback) { + callback(response, textStatus, jqXHR); + } + + }); } /** @@ -392,7 +345,6 @@ var PetApi = function PetApi() { * @return void */ self.deletePet = function(petId, apiKey, callback) { - var postBody = null; var postBinaryBody = null; @@ -410,8 +362,8 @@ var PetApi = function PetApi() { basePath = basePath.substring(0, basePath.length-1); } - var path = basePath + replaceAll(replaceAll("/pet/{petId}", "\\{format\\}","json") -, "\\{" + "petId" + "\\}", apiClient.escapeString(petId.toString())); + var path = basePath + replaceAll(replaceAll("/pet/{petId}", "\\{format\\}","json") +, "\\{" + "petId" + "\\}", petId.toString()); var queryParams = {}; var headerParams = {}; @@ -423,22 +375,22 @@ var PetApi = function PetApi() { - path += createQueryString(queryParams); - - //if (console) { - //console.log('path: ' + path); - //console.log('queryParams: ' + queryParams); - //} + path += createQueryString(queryParams); + var options = {type: "DELETE", async: true, contentType: "application/json", dataType: "json", data: postBody}; + var request = $.ajax(path, options); + //request.fail(function(jqXHR, textStatus, errorThrown){ + // errorHandler(jqXHR, textStatus, errorThrown); + //}); - - - - apiClient.invokeAPI(path, "DELETE", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, null); - - - - + + request.done(function(response, textStatus, jqXHR){ + + if (callback) { + callback(response, textStatus, jqXHR); + } + + }); } /** @@ -451,7 +403,6 @@ var PetApi = function PetApi() { * @return void */ self.uploadFile = function(petId, additionalMetadata, file, callback) { - var postBody = null; var postBinaryBody = null; @@ -469,8 +420,8 @@ var PetApi = function PetApi() { basePath = basePath.substring(0, basePath.length-1); } - var path = basePath + replaceAll(replaceAll("/pet/{petId}/uploadImage", "\\{format\\}","json") -, "\\{" + "petId" + "\\}", apiClient.escapeString(petId.toString())); + var path = basePath + replaceAll(replaceAll("/pet/{petId}/uploadImage", "\\{format\\}","json") +, "\\{" + "petId" + "\\}", petId.toString()); var queryParams = {}; var headerParams = {}; @@ -484,25 +435,25 @@ var PetApi = function PetApi() { formParams.put("file", file); - path += createQueryString(queryParams); - - //if (console) { - //console.log('path: ' + path); - //console.log('queryParams: ' + queryParams); - //} + path += createQueryString(queryParams); + var options = {type: "POST", async: true, contentType: "application/json", dataType: "json", data: postBody}; + var request = $.ajax(path, options); + //request.fail(function(jqXHR, textStatus, errorThrown){ + // errorHandler(jqXHR, textStatus, errorThrown); + //}); - - - - apiClient.invokeAPI(path, "POST", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, null); - - - - + + request.done(function(response, textStatus, jqXHR){ + + if (callback) { + callback(response, textStatus, jqXHR); + } + + }); } - + function replaceAll (haystack, needle, replace) { var result= haystack; @@ -533,4 +484,4 @@ var PetApi = function PetApi() { // export module for Node.js if (typeof module === 'object' && module.exports) { module.exports = PetApi; -} \ No newline at end of file +} diff --git a/samples/client/petstore/javascript/src/api/StoreApi.js b/samples/client/petstore/javascript/src/api/StoreApi.js index 7a20d8841a36..6cfa53744bac 100644 --- a/samples/client/petstore/javascript/src/api/StoreApi.js +++ b/samples/client/petstore/javascript/src/api/StoreApi.js @@ -15,6 +15,7 @@ if ( typeof define === "function" && define.amd ) { var StoreApi = function StoreApi() { var self = this; + /** * Returns pet inventories by status * Returns a map of status codes to quantities @@ -22,7 +23,6 @@ var StoreApi = function StoreApi() { * @return Object */ self.getInventory = function(callback) { - var postBody = null; var postBinaryBody = null; @@ -33,7 +33,7 @@ var StoreApi = function StoreApi() { basePath = basePath.substring(0, basePath.length-1); } - var path = basePath + replaceAll(replaceAll("/store/inventory", "\\{format\\}","json")); + var path = basePath + replaceAll(replaceAll("/store/inventory", "\\{format\\}","json")); var queryParams = {}; var headerParams = {}; @@ -43,41 +43,27 @@ var StoreApi = function StoreApi() { - path += createQueryString(queryParams); + path += createQueryString(queryParams); - //if (console) { - //console.log('path: ' + path); - //console.log('queryParams: ' + queryParams); - //} - - - - - - //TypeRef returnType = new TypeRef>() {}; - //return apiClient.invokeAPI(path, "GET", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, returnType); - - var options = {type: "GET", async: true, contentType: "application/json", dataType: "json", data: postBody}; + var options = {type: "GET", async: true, contentType: "application/json", dataType: "json", data: postBody}; var request = $.ajax(path, options); //request.fail(function(jqXHR, textStatus, errorThrown){ // errorHandler(jqXHR, textStatus, errorThrown); //}); - request.done(function(response, textStatus, jqXHR){ - /** - * @returns Object - */ - var myResponse = response; - - - callback(myResponse, textStatus, jqXHR); - }); - - - - - + request.done(function(response, textStatus, jqXHR){ + + /** + * @returns Object + */ + var myResponse = response; + + if (callback) { + callback(myResponse, textStatus, jqXHR); + } + + }); } /** @@ -88,7 +74,6 @@ var StoreApi = function StoreApi() { * @return Order */ self.placeOrder = function(body, callback) { - var postBody = JSON.stringify(body); var postBinaryBody = null; @@ -99,7 +84,7 @@ var StoreApi = function StoreApi() { basePath = basePath.substring(0, basePath.length-1); } - var path = basePath + replaceAll(replaceAll("/store/order", "\\{format\\}","json")); + var path = basePath + replaceAll(replaceAll("/store/order", "\\{format\\}","json")); var queryParams = {}; var headerParams = {}; @@ -109,42 +94,28 @@ var StoreApi = function StoreApi() { - path += createQueryString(queryParams); + path += createQueryString(queryParams); - //if (console) { - //console.log('path: ' + path); - //console.log('queryParams: ' + queryParams); - //} - - - - - - //TypeRef returnType = new TypeRef() {}; - //return apiClient.invokeAPI(path, "POST", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, returnType); - - var options = {type: "POST", async: true, contentType: "application/json", dataType: "json", data: postBody}; + var options = {type: "POST", async: true, contentType: "application/json", dataType: "json", data: postBody}; var request = $.ajax(path, options); //request.fail(function(jqXHR, textStatus, errorThrown){ // errorHandler(jqXHR, textStatus, errorThrown); //}); - request.done(function(response, textStatus, jqXHR){ - /** - * @returns Order - */ - - var myResponse = new Order(); - myResponse.constructFromObject(response); - - callback(myResponse, textStatus, jqXHR); - }); - - - - - + request.done(function(response, textStatus, jqXHR){ + + /** + * @returns Order + */ + + var myResponse = new Order(); + myResponse.constructFromObject(response); + if (callback) { + callback(myResponse, textStatus, jqXHR); + } + + }); } /** @@ -155,7 +126,6 @@ var StoreApi = function StoreApi() { * @return Order */ self.getOrderById = function(orderId, callback) { - var postBody = null; var postBinaryBody = null; @@ -173,8 +143,8 @@ var StoreApi = function StoreApi() { basePath = basePath.substring(0, basePath.length-1); } - var path = basePath + replaceAll(replaceAll("/store/order/{orderId}", "\\{format\\}","json") -, "\\{" + "orderId" + "\\}", apiClient.escapeString(orderId.toString())); + var path = basePath + replaceAll(replaceAll("/store/order/{orderId}", "\\{format\\}","json") +, "\\{" + "orderId" + "\\}", orderId.toString()); var queryParams = {}; var headerParams = {}; @@ -184,42 +154,28 @@ var StoreApi = function StoreApi() { - path += createQueryString(queryParams); + path += createQueryString(queryParams); - //if (console) { - //console.log('path: ' + path); - //console.log('queryParams: ' + queryParams); - //} - - - - - - //TypeRef returnType = new TypeRef() {}; - //return apiClient.invokeAPI(path, "GET", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, returnType); - - var options = {type: "GET", async: true, contentType: "application/json", dataType: "json", data: postBody}; + var options = {type: "GET", async: true, contentType: "application/json", dataType: "json", data: postBody}; var request = $.ajax(path, options); //request.fail(function(jqXHR, textStatus, errorThrown){ // errorHandler(jqXHR, textStatus, errorThrown); //}); - request.done(function(response, textStatus, jqXHR){ - /** - * @returns Order - */ - - var myResponse = new Order(); - myResponse.constructFromObject(response); - - callback(myResponse, textStatus, jqXHR); - }); - - - - - + request.done(function(response, textStatus, jqXHR){ + + /** + * @returns Order + */ + + var myResponse = new Order(); + myResponse.constructFromObject(response); + if (callback) { + callback(myResponse, textStatus, jqXHR); + } + + }); } /** @@ -230,7 +186,6 @@ var StoreApi = function StoreApi() { * @return void */ self.deleteOrder = function(orderId, callback) { - var postBody = null; var postBinaryBody = null; @@ -248,8 +203,8 @@ var StoreApi = function StoreApi() { basePath = basePath.substring(0, basePath.length-1); } - var path = basePath + replaceAll(replaceAll("/store/order/{orderId}", "\\{format\\}","json") -, "\\{" + "orderId" + "\\}", apiClient.escapeString(orderId.toString())); + var path = basePath + replaceAll(replaceAll("/store/order/{orderId}", "\\{format\\}","json") +, "\\{" + "orderId" + "\\}", orderId.toString()); var queryParams = {}; var headerParams = {}; @@ -259,25 +214,25 @@ var StoreApi = function StoreApi() { - path += createQueryString(queryParams); - - //if (console) { - //console.log('path: ' + path); - //console.log('queryParams: ' + queryParams); - //} + path += createQueryString(queryParams); + var options = {type: "DELETE", async: true, contentType: "application/json", dataType: "json", data: postBody}; + var request = $.ajax(path, options); + //request.fail(function(jqXHR, textStatus, errorThrown){ + // errorHandler(jqXHR, textStatus, errorThrown); + //}); - - - - apiClient.invokeAPI(path, "DELETE", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, null); - - - - + + request.done(function(response, textStatus, jqXHR){ + + if (callback) { + callback(response, textStatus, jqXHR); + } + + }); } - + function replaceAll (haystack, needle, replace) { var result= haystack; @@ -308,4 +263,4 @@ var StoreApi = function StoreApi() { // export module for Node.js if (typeof module === 'object' && module.exports) { module.exports = StoreApi; -} \ No newline at end of file +} diff --git a/samples/client/petstore/javascript/src/api/UserApi.js b/samples/client/petstore/javascript/src/api/UserApi.js index 72dc3f3d198e..bfa1b1c16c8f 100644 --- a/samples/client/petstore/javascript/src/api/UserApi.js +++ b/samples/client/petstore/javascript/src/api/UserApi.js @@ -15,6 +15,7 @@ if ( typeof define === "function" && define.amd ) { var UserApi = function UserApi() { var self = this; + /** * Create user * This can only be done by the logged in user. @@ -23,7 +24,6 @@ var UserApi = function UserApi() { * @return void */ self.createUser = function(body, callback) { - var postBody = JSON.stringify(body); var postBinaryBody = null; @@ -34,7 +34,7 @@ var UserApi = function UserApi() { basePath = basePath.substring(0, basePath.length-1); } - var path = basePath + replaceAll(replaceAll("/user", "\\{format\\}","json")); + var path = basePath + replaceAll(replaceAll("/user", "\\{format\\}","json")); var queryParams = {}; var headerParams = {}; @@ -44,22 +44,22 @@ var UserApi = function UserApi() { - path += createQueryString(queryParams); - - //if (console) { - //console.log('path: ' + path); - //console.log('queryParams: ' + queryParams); - //} + path += createQueryString(queryParams); + var options = {type: "POST", async: true, contentType: "application/json", dataType: "json", data: postBody}; + var request = $.ajax(path, options); + //request.fail(function(jqXHR, textStatus, errorThrown){ + // errorHandler(jqXHR, textStatus, errorThrown); + //}); - - - - apiClient.invokeAPI(path, "POST", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, null); - - - - + + request.done(function(response, textStatus, jqXHR){ + + if (callback) { + callback(response, textStatus, jqXHR); + } + + }); } /** @@ -70,7 +70,6 @@ var UserApi = function UserApi() { * @return void */ self.createUsersWithArrayInput = function(body, callback) { - var postBody = JSON.stringify(body); var postBinaryBody = null; @@ -81,7 +80,7 @@ var UserApi = function UserApi() { basePath = basePath.substring(0, basePath.length-1); } - var path = basePath + replaceAll(replaceAll("/user/createWithArray", "\\{format\\}","json")); + var path = basePath + replaceAll(replaceAll("/user/createWithArray", "\\{format\\}","json")); var queryParams = {}; var headerParams = {}; @@ -91,22 +90,22 @@ var UserApi = function UserApi() { - path += createQueryString(queryParams); - - //if (console) { - //console.log('path: ' + path); - //console.log('queryParams: ' + queryParams); - //} + path += createQueryString(queryParams); + var options = {type: "POST", async: true, contentType: "application/json", dataType: "json", data: postBody}; + var request = $.ajax(path, options); + //request.fail(function(jqXHR, textStatus, errorThrown){ + // errorHandler(jqXHR, textStatus, errorThrown); + //}); - - - - apiClient.invokeAPI(path, "POST", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, null); - - - - + + request.done(function(response, textStatus, jqXHR){ + + if (callback) { + callback(response, textStatus, jqXHR); + } + + }); } /** @@ -117,7 +116,6 @@ var UserApi = function UserApi() { * @return void */ self.createUsersWithListInput = function(body, callback) { - var postBody = JSON.stringify(body); var postBinaryBody = null; @@ -128,7 +126,7 @@ var UserApi = function UserApi() { basePath = basePath.substring(0, basePath.length-1); } - var path = basePath + replaceAll(replaceAll("/user/createWithList", "\\{format\\}","json")); + var path = basePath + replaceAll(replaceAll("/user/createWithList", "\\{format\\}","json")); var queryParams = {}; var headerParams = {}; @@ -138,22 +136,22 @@ var UserApi = function UserApi() { - path += createQueryString(queryParams); - - //if (console) { - //console.log('path: ' + path); - //console.log('queryParams: ' + queryParams); - //} + path += createQueryString(queryParams); + var options = {type: "POST", async: true, contentType: "application/json", dataType: "json", data: postBody}; + var request = $.ajax(path, options); + //request.fail(function(jqXHR, textStatus, errorThrown){ + // errorHandler(jqXHR, textStatus, errorThrown); + //}); - - - - apiClient.invokeAPI(path, "POST", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, null); - - - - + + request.done(function(response, textStatus, jqXHR){ + + if (callback) { + callback(response, textStatus, jqXHR); + } + + }); } /** @@ -165,7 +163,6 @@ var UserApi = function UserApi() { * @return String */ self.loginUser = function(username, password, callback) { - var postBody = null; var postBinaryBody = null; @@ -176,7 +173,7 @@ var UserApi = function UserApi() { basePath = basePath.substring(0, basePath.length-1); } - var path = basePath + replaceAll(replaceAll("/user/login", "\\{format\\}","json")); + var path = basePath + replaceAll(replaceAll("/user/login", "\\{format\\}","json")); var queryParams = {}; var headerParams = {}; @@ -190,41 +187,27 @@ var UserApi = function UserApi() { - path += createQueryString(queryParams); + path += createQueryString(queryParams); - //if (console) { - //console.log('path: ' + path); - //console.log('queryParams: ' + queryParams); - //} - - - - - - //TypeRef returnType = new TypeRef() {}; - //return apiClient.invokeAPI(path, "GET", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, returnType); - - var options = {type: "GET", async: true, contentType: "application/json", dataType: "json", data: postBody}; + var options = {type: "GET", async: true, contentType: "application/json", dataType: "json", data: postBody}; var request = $.ajax(path, options); //request.fail(function(jqXHR, textStatus, errorThrown){ // errorHandler(jqXHR, textStatus, errorThrown); //}); - request.done(function(response, textStatus, jqXHR){ - /** - * @returns String - */ - var myResponse = response; - - - callback(myResponse, textStatus, jqXHR); - }); - - - - - + request.done(function(response, textStatus, jqXHR){ + + /** + * @returns String + */ + var myResponse = response; + + if (callback) { + callback(myResponse, textStatus, jqXHR); + } + + }); } /** @@ -234,7 +217,6 @@ var UserApi = function UserApi() { * @return void */ self.logoutUser = function(callback) { - var postBody = null; var postBinaryBody = null; @@ -245,7 +227,7 @@ var UserApi = function UserApi() { basePath = basePath.substring(0, basePath.length-1); } - var path = basePath + replaceAll(replaceAll("/user/logout", "\\{format\\}","json")); + var path = basePath + replaceAll(replaceAll("/user/logout", "\\{format\\}","json")); var queryParams = {}; var headerParams = {}; @@ -255,22 +237,22 @@ var UserApi = function UserApi() { - path += createQueryString(queryParams); - - //if (console) { - //console.log('path: ' + path); - //console.log('queryParams: ' + queryParams); - //} + path += createQueryString(queryParams); + var options = {type: "GET", async: true, contentType: "application/json", dataType: "json", data: postBody}; + var request = $.ajax(path, options); + //request.fail(function(jqXHR, textStatus, errorThrown){ + // errorHandler(jqXHR, textStatus, errorThrown); + //}); - - - - apiClient.invokeAPI(path, "GET", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, null); - - - - + + request.done(function(response, textStatus, jqXHR){ + + if (callback) { + callback(response, textStatus, jqXHR); + } + + }); } /** @@ -281,7 +263,6 @@ var UserApi = function UserApi() { * @return User */ self.getUserByName = function(username, callback) { - var postBody = null; var postBinaryBody = null; @@ -299,8 +280,8 @@ var UserApi = function UserApi() { basePath = basePath.substring(0, basePath.length-1); } - var path = basePath + replaceAll(replaceAll("/user/{username}", "\\{format\\}","json") -, "\\{" + "username" + "\\}", apiClient.escapeString(username.toString())); + var path = basePath + replaceAll(replaceAll("/user/{username}", "\\{format\\}","json") +, "\\{" + "username" + "\\}", username.toString()); var queryParams = {}; var headerParams = {}; @@ -310,42 +291,28 @@ var UserApi = function UserApi() { - path += createQueryString(queryParams); + path += createQueryString(queryParams); - //if (console) { - //console.log('path: ' + path); - //console.log('queryParams: ' + queryParams); - //} - - - - - - //TypeRef returnType = new TypeRef() {}; - //return apiClient.invokeAPI(path, "GET", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, returnType); - - var options = {type: "GET", async: true, contentType: "application/json", dataType: "json", data: postBody}; + var options = {type: "GET", async: true, contentType: "application/json", dataType: "json", data: postBody}; var request = $.ajax(path, options); //request.fail(function(jqXHR, textStatus, errorThrown){ // errorHandler(jqXHR, textStatus, errorThrown); //}); - request.done(function(response, textStatus, jqXHR){ - /** - * @returns User - */ - - var myResponse = new User(); - myResponse.constructFromObject(response); - - callback(myResponse, textStatus, jqXHR); - }); - - - - - + request.done(function(response, textStatus, jqXHR){ + + /** + * @returns User + */ + + var myResponse = new User(); + myResponse.constructFromObject(response); + if (callback) { + callback(myResponse, textStatus, jqXHR); + } + + }); } /** @@ -357,7 +324,6 @@ var UserApi = function UserApi() { * @return void */ self.updateUser = function(username, body, callback) { - var postBody = JSON.stringify(body); var postBinaryBody = null; @@ -375,8 +341,8 @@ var UserApi = function UserApi() { basePath = basePath.substring(0, basePath.length-1); } - var path = basePath + replaceAll(replaceAll("/user/{username}", "\\{format\\}","json") -, "\\{" + "username" + "\\}", apiClient.escapeString(username.toString())); + var path = basePath + replaceAll(replaceAll("/user/{username}", "\\{format\\}","json") +, "\\{" + "username" + "\\}", username.toString()); var queryParams = {}; var headerParams = {}; @@ -386,22 +352,22 @@ var UserApi = function UserApi() { - path += createQueryString(queryParams); - - //if (console) { - //console.log('path: ' + path); - //console.log('queryParams: ' + queryParams); - //} + path += createQueryString(queryParams); + var options = {type: "PUT", async: true, contentType: "application/json", dataType: "json", data: postBody}; + var request = $.ajax(path, options); + //request.fail(function(jqXHR, textStatus, errorThrown){ + // errorHandler(jqXHR, textStatus, errorThrown); + //}); - - - - apiClient.invokeAPI(path, "PUT", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, null); - - - - + + request.done(function(response, textStatus, jqXHR){ + + if (callback) { + callback(response, textStatus, jqXHR); + } + + }); } /** @@ -412,7 +378,6 @@ var UserApi = function UserApi() { * @return void */ self.deleteUser = function(username, callback) { - var postBody = null; var postBinaryBody = null; @@ -430,8 +395,8 @@ var UserApi = function UserApi() { basePath = basePath.substring(0, basePath.length-1); } - var path = basePath + replaceAll(replaceAll("/user/{username}", "\\{format\\}","json") -, "\\{" + "username" + "\\}", apiClient.escapeString(username.toString())); + var path = basePath + replaceAll(replaceAll("/user/{username}", "\\{format\\}","json") +, "\\{" + "username" + "\\}", username.toString()); var queryParams = {}; var headerParams = {}; @@ -441,25 +406,25 @@ var UserApi = function UserApi() { - path += createQueryString(queryParams); - - //if (console) { - //console.log('path: ' + path); - //console.log('queryParams: ' + queryParams); - //} + path += createQueryString(queryParams); + var options = {type: "DELETE", async: true, contentType: "application/json", dataType: "json", data: postBody}; + var request = $.ajax(path, options); + //request.fail(function(jqXHR, textStatus, errorThrown){ + // errorHandler(jqXHR, textStatus, errorThrown); + //}); - - - - apiClient.invokeAPI(path, "DELETE", queryParams, postBody, postBinaryBody, headerParams, formParams, accept, contentType, authNames, null); - - - - + + request.done(function(response, textStatus, jqXHR){ + + if (callback) { + callback(response, textStatus, jqXHR); + } + + }); } - + function replaceAll (haystack, needle, replace) { var result= haystack; @@ -490,4 +455,4 @@ var UserApi = function UserApi() { // export module for Node.js if (typeof module === 'object' && module.exports) { module.exports = UserApi; -} \ No newline at end of file +} diff --git a/samples/client/petstore/javascript/test/api/PetApiTest.js b/samples/client/petstore/javascript/test/api/PetApiTest.js new file mode 100644 index 000000000000..122dde3982fd --- /dev/null +++ b/samples/client/petstore/javascript/test/api/PetApiTest.js @@ -0,0 +1,183 @@ +if (typeof module === 'object' && module.exports) { + var expect = require('expect.js'); + var requireApiWithMocks = require('../helper.js').requireApiWithMocks; + var PetApi = requireApiWithMocks('PetApi'); + var Pet = require('../../src/model/Pet'); + var Category = require('../../src/model/Category'); + var Tag = require('../../src/model/Tag'); +} + +var api; + +beforeEach(function() { + api = new PetApi(); +}); + +var createRandomPet = function() { + var id = new Date().getTime(); + var pet = new Pet(); + pet.setId(id); + pet.setName("gorilla" + id); + + var category = new Category(); + category.setName("really-happy"); + pet.setCategory(category); + + pet.setStatus('available'); + var photos = ["http://foo.bar.com/1", "http://foo.bar.com/2"]; + pet.setPhotoUrls(photos); + + return pet; +}; + +describe('PetApi', function() { + it('should create and get pet', function (done) { + var pet = createRandomPet(); + api.addPet(pet); + + api.getPetById(pet.id, function(fetched, textStatus, jqXHR) { + expect(textStatus).to.be('success'); + expect(fetched).to.be.ok(); + expect(fetched.id).to.be(pet.id); + expect(fetched.getCategory()).to.be.ok(); + expect(fetched.getCategory().getName()).to.be(pet.getCategory().getName()); + done(); + }); + }); +}); + +/* + @Test + public void testUpdatePet() throws Exception { + Pet pet = createRandomPet(); + pet.setName("programmer"); + + api.updatePet(pet); + + Pet fetched = api.getPetById(pet.getId()); + assertNotNull(fetched); + assertEquals(pet.getId(), fetched.getId()); + assertNotNull(fetched.getCategory()); + assertEquals(fetched.getCategory().getName(), pet.getCategory().getName()); + } + + @Test + public void testFindPetsByStatus() throws Exception { + Pet pet = createRandomPet(); + pet.setName("programmer"); + pet.setStatus(Pet.StatusEnum.AVAILABLE); + + api.updatePet(pet); + + List pets = api.findPetsByStatus(Arrays.asList(new String[]{"available"})); + assertNotNull(pets); + + boolean found = false; + for (Pet fetched : pets) { + if (fetched.getId().equals(pet.getId())) { + found = true; + break; + } + } + + assertTrue(found); + } + + @Test + public void testFindPetsByTags() throws Exception { + Pet pet = createRandomPet(); + pet.setName("monster"); + pet.setStatus(Pet.StatusEnum.AVAILABLE); + + List tags = new ArrayList(); + Tag tag1 = new Tag(); + tag1.setName("friendly"); + tags.add(tag1); + pet.setTags(tags); + + api.updatePet(pet); + + List pets = api.findPetsByTags(Arrays.asList(new String[]{"friendly"})); + assertNotNull(pets); + + boolean found = false; + for (Pet fetched : pets) { + if (fetched.getId().equals(pet.getId())) { + found = true; + break; + } + } + assertTrue(found); + } + + @Test + public void testUpdatePetWithForm() throws Exception { + Pet pet = createRandomPet(); + pet.setName("frank"); + api.addPet(pet); + + Pet fetched = api.getPetById(pet.getId()); + + api.updatePetWithForm(String.valueOf(fetched.getId()), "furt", null); + Pet updated = api.getPetById(fetched.getId()); + + assertEquals(updated.getName(), "furt"); + } + + @Test + public void testDeletePet() throws Exception { + Pet pet = createRandomPet(); + api.addPet(pet); + + Pet fetched = api.getPetById(pet.getId()); + api.deletePet(fetched.getId(), null); + + try { + fetched = api.getPetById(fetched.getId()); + fail("expected an error"); + } catch (ApiException e) { + assertEquals(404, e.getCode()); + } + } + + @Test + public void testUploadFile() throws Exception { + Pet pet = createRandomPet(); + api.addPet(pet); + + File file = new File("hello.txt"); + BufferedWriter writer = new BufferedWriter(new FileWriter(file)); + writer.write("Hello world!"); + writer.close(); + + api.uploadFile(pet.getId(), "a test file", new File(file.getAbsolutePath())); + } + + @Test + public void testEqualsAndHashCode() { + Pet pet1 = new Pet(); + Pet pet2 = new Pet(); + assertTrue(pet1.equals(pet2)); + assertTrue(pet2.equals(pet1)); + assertTrue(pet1.hashCode() == pet2.hashCode()); + assertTrue(pet1.equals(pet1)); + assertTrue(pet1.hashCode() == pet1.hashCode()); + + pet2.setName("really-happy"); + pet2.setPhotoUrls(Arrays.asList(new String[]{"http://foo.bar.com/1", "http://foo.bar.com/2"})); + assertFalse(pet1.equals(pet2)); + assertFalse(pet2.equals(pet1)); + assertFalse(pet1.hashCode() == (pet2.hashCode())); + assertTrue(pet2.equals(pet2)); + assertTrue(pet2.hashCode() == pet2.hashCode()); + + pet1.setName("really-happy"); + pet1.setPhotoUrls(Arrays.asList(new String[]{"http://foo.bar.com/1", "http://foo.bar.com/2"})); + assertTrue(pet1.equals(pet2)); + assertTrue(pet2.equals(pet1)); + assertTrue(pet1.hashCode() == pet2.hashCode()); + assertTrue(pet1.equals(pet1)); + assertTrue(pet1.hashCode() == pet1.hashCode()); + } +} +*/ diff --git a/samples/client/petstore/javascript/test/helper.js b/samples/client/petstore/javascript/test/helper.js index a1b798f325f4..018b6428af66 100644 --- a/samples/client/petstore/javascript/test/helper.js +++ b/samples/client/petstore/javascript/test/helper.js @@ -10,10 +10,10 @@ $.ajaxSettings.xhr = function() { return new XMLHttpRequest(); }; -var requireWithMocks = function(path) { - return mockrequire(path, { +var requireApiWithMocks = function(path) { + return mockrequire('../src/api/' + path, { 'jquery': $ }); }; -exports.requireWithMocks = requireWithMocks; +exports.requireApiWithMocks = requireApiWithMocks; diff --git a/samples/client/petstore/javascript/test/run_tests.html b/samples/client/petstore/javascript/test/run_tests.html index 9f2d78ad0b86..d4b9e6c9f652 100644 --- a/samples/client/petstore/javascript/test/run_tests.html +++ b/samples/client/petstore/javascript/test/run_tests.html @@ -11,19 +11,19 @@ - - - - - - - + + + + + + + From a58f755a6a596261857b807d8ddddb9fed9df282 Mon Sep 17 00:00:00 2001 From: xhh Date: Thu, 17 Dec 2015 21:19:28 +0800 Subject: [PATCH 69/71] Escape path parameters with encodeURIComponent and tweak the test command --- .../src/main/resources/Javascript/api.mustache | 2 +- .../src/main/resources/Javascript/package.mustache | 2 +- samples/client/petstore/javascript/package.json | 2 +- samples/client/petstore/javascript/pom.xml | 4 ++-- samples/client/petstore/javascript/src/api/PetApi.js | 8 ++++---- samples/client/petstore/javascript/src/api/StoreApi.js | 4 ++-- samples/client/petstore/javascript/src/api/UserApi.js | 6 +++--- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/modules/swagger-codegen/src/main/resources/Javascript/api.mustache b/modules/swagger-codegen/src/main/resources/Javascript/api.mustache index 21734396695f..0236f6a61be2 100644 --- a/modules/swagger-codegen/src/main/resources/Javascript/api.mustache +++ b/modules/swagger-codegen/src/main/resources/Javascript/api.mustache @@ -42,7 +42,7 @@ var {{classname}} = function {{classname}}() { } var {{localVariablePrefix}}path = basePath + replaceAll(replaceAll("{{{path}}}", "\\{format\\}","json"){{#pathParams}} -, "\\{" + "{{baseName}}" + "\\}", {{localVariablePrefix}}{{{paramName}}}.toString(){{/pathParams}}); +, "\\{" + "{{baseName}}" + "\\}", encodeURIComponent({{localVariablePrefix}}{{{paramName}}}.toString()){{/pathParams}}); var queryParams = {}; var headerParams = {}; diff --git a/modules/swagger-codegen/src/main/resources/Javascript/package.mustache b/modules/swagger-codegen/src/main/resources/Javascript/package.mustache index 53bbed30be93..c77ee835709e 100644 --- a/modules/swagger-codegen/src/main/resources/Javascript/package.mustache +++ b/modules/swagger-codegen/src/main/resources/Javascript/package.mustache @@ -5,7 +5,7 @@ "license": "{{{projectLicenseName}}}",{{/projectLicenseName}} "main": "{{sourceFolder}}/index.js", "scripts": { - "test": "./node_modules/mocha/bin/mocha" + "test": "./node_modules/mocha/bin/mocha --recursive" }, "dependencies": { "jquery": "~2.1.4" diff --git a/samples/client/petstore/javascript/package.json b/samples/client/petstore/javascript/package.json index 156300cf760f..6810fd633de5 100644 --- a/samples/client/petstore/javascript/package.json +++ b/samples/client/petstore/javascript/package.json @@ -5,7 +5,7 @@ "license": "Apache 2.0", "main": "src/index.js", "scripts": { - "test": "./node_modules/mocha/bin/mocha" + "test": "./node_modules/mocha/bin/mocha --recursive" }, "dependencies": { "jquery": "~2.1.4" diff --git a/samples/client/petstore/javascript/pom.xml b/samples/client/petstore/javascript/pom.xml index 82d13ff17ca2..b7a17c92b79c 100644 --- a/samples/client/petstore/javascript/pom.xml +++ b/samples/client/petstore/javascript/pom.xml @@ -32,9 +32,9 @@ exec - mocha + npm - --recursive + test diff --git a/samples/client/petstore/javascript/src/api/PetApi.js b/samples/client/petstore/javascript/src/api/PetApi.js index fcc769d2f269..3d5eb1dc9e5c 100644 --- a/samples/client/petstore/javascript/src/api/PetApi.js +++ b/samples/client/petstore/javascript/src/api/PetApi.js @@ -262,7 +262,7 @@ var PetApi = function PetApi() { } var path = basePath + replaceAll(replaceAll("/pet/{petId}", "\\{format\\}","json") -, "\\{" + "petId" + "\\}", petId.toString()); +, "\\{" + "petId" + "\\}", encodeURIComponent(petId.toString())); var queryParams = {}; var headerParams = {}; @@ -329,7 +329,7 @@ var PetApi = function PetApi() { } var path = basePath + replaceAll(replaceAll("/pet/{petId}", "\\{format\\}","json") -, "\\{" + "petId" + "\\}", petId.toString()); +, "\\{" + "petId" + "\\}", encodeURIComponent(petId.toString())); var queryParams = {}; var headerParams = {}; @@ -393,7 +393,7 @@ var PetApi = function PetApi() { } var path = basePath + replaceAll(replaceAll("/pet/{petId}", "\\{format\\}","json") -, "\\{" + "petId" + "\\}", petId.toString()); +, "\\{" + "petId" + "\\}", encodeURIComponent(petId.toString())); var queryParams = {}; var headerParams = {}; @@ -456,7 +456,7 @@ var PetApi = function PetApi() { } var path = basePath + replaceAll(replaceAll("/pet/{petId}/uploadImage", "\\{format\\}","json") -, "\\{" + "petId" + "\\}", petId.toString()); +, "\\{" + "petId" + "\\}", encodeURIComponent(petId.toString())); var queryParams = {}; var headerParams = {}; diff --git a/samples/client/petstore/javascript/src/api/StoreApi.js b/samples/client/petstore/javascript/src/api/StoreApi.js index a05bf10f1796..e52a31059645 100644 --- a/samples/client/petstore/javascript/src/api/StoreApi.js +++ b/samples/client/petstore/javascript/src/api/StoreApi.js @@ -154,7 +154,7 @@ var StoreApi = function StoreApi() { } var path = basePath + replaceAll(replaceAll("/store/order/{orderId}", "\\{format\\}","json") -, "\\{" + "orderId" + "\\}", orderId.toString()); +, "\\{" + "orderId" + "\\}", encodeURIComponent(orderId.toString())); var queryParams = {}; var headerParams = {}; @@ -219,7 +219,7 @@ var StoreApi = function StoreApi() { } var path = basePath + replaceAll(replaceAll("/store/order/{orderId}", "\\{format\\}","json") -, "\\{" + "orderId" + "\\}", orderId.toString()); +, "\\{" + "orderId" + "\\}", encodeURIComponent(orderId.toString())); var queryParams = {}; var headerParams = {}; diff --git a/samples/client/petstore/javascript/src/api/UserApi.js b/samples/client/petstore/javascript/src/api/UserApi.js index 32dcafbfc7ad..148e6171ed40 100644 --- a/samples/client/petstore/javascript/src/api/UserApi.js +++ b/samples/client/petstore/javascript/src/api/UserApi.js @@ -306,7 +306,7 @@ var UserApi = function UserApi() { } var path = basePath + replaceAll(replaceAll("/user/{username}", "\\{format\\}","json") -, "\\{" + "username" + "\\}", username.toString()); +, "\\{" + "username" + "\\}", encodeURIComponent(username.toString())); var queryParams = {}; var headerParams = {}; @@ -372,7 +372,7 @@ var UserApi = function UserApi() { } var path = basePath + replaceAll(replaceAll("/user/{username}", "\\{format\\}","json") -, "\\{" + "username" + "\\}", username.toString()); +, "\\{" + "username" + "\\}", encodeURIComponent(username.toString())); var queryParams = {}; var headerParams = {}; @@ -431,7 +431,7 @@ var UserApi = function UserApi() { } var path = basePath + replaceAll(replaceAll("/user/{username}", "\\{format\\}","json") -, "\\{" + "username" + "\\}", username.toString()); +, "\\{" + "username" + "\\}", encodeURIComponent(username.toString())); var queryParams = {}; var headerParams = {}; From 1b0294dac0258bc7c179883d1f41174a7ef628fc Mon Sep 17 00:00:00 2001 From: xhh Date: Thu, 17 Dec 2015 21:29:05 +0800 Subject: [PATCH 70/71] Javascript: fix the constructFromObject issue Closes #1721 Also fixed indentations in models --- .../main/resources/Javascript/model.mustache | 49 +++--- .../petstore/javascript/src/model/Category.js | 55 ++++--- .../petstore/javascript/src/model/Order.js | 121 +++++++------- .../petstore/javascript/src/model/Pet.js | 125 +++++++------- .../petstore/javascript/src/model/Tag.js | 55 ++++--- .../petstore/javascript/src/model/User.js | 153 +++++++++--------- 6 files changed, 288 insertions(+), 270 deletions(-) diff --git a/modules/swagger-codegen/src/main/resources/Javascript/model.mustache b/modules/swagger-codegen/src/main/resources/Javascript/model.mustache index 8b021a3badd3..0588d03a8c13 100644 --- a/modules/swagger-codegen/src/main/resources/Javascript/model.mustache +++ b/modules/swagger-codegen/src/main/resources/Javascript/model.mustache @@ -12,34 +12,37 @@ if (typeof module === 'object' && module.exports) { //export module if ( typeof define === "function" && define.amd ) { - define('{{classname}}', ['jquery'{{#vars}}{{^isPrimitiveType}}{{^-last}}, {{/-last}}'{{datatypeWithEnum}}'{{/isPrimitiveType}}{{/vars}}], - function(${{#vars}}{{^isPrimitiveType}}{{^-last}}, {{/-last}}{{datatypeWithEnum}}{{/isPrimitiveType}}{{/vars}}) { - return {{classname}}; - }); + define('{{classname}}', ['jquery'{{#vars}}{{^isPrimitiveType}}{{^-last}}, {{/-last}}'{{datatypeWithEnum}}'{{/isPrimitiveType}}{{/vars}}], + function(${{#vars}}{{^isPrimitiveType}}{{^-last}}, {{/-last}}{{datatypeWithEnum}}{{/isPrimitiveType}}{{/vars}}) { + return {{classname}}; + }); } {{#description}}/** * {{description}} **/{{/description}} var {{classname}} = function {{classname}}({{#mandatory}}{{this}}{{^-last}}, {{/-last}}{{/mandatory}}) { {{#parent}}/* extends {{{parent}}}*/{{/parent}} - var self = this; - {{#vars}} - /**{{#description}} - * {{{description}}}{{/description}} - * datatype: {{{datatypeWithEnum}}}{{#required}} - * required{{/required}}{{#minimum}} - * minimum: {{minimum}}{{/minimum}}{{#maximum}} - * maximum: {{maximum}}{{/maximum}} - **/ - self.{{name}} = {{#required}}{{name}}{{/required}}{{^required}}{{{defaultValue}}}{{/required}}; - {{/vars}} - - self.constructFromObject = function(data) { - {{#vars}} - self.{{name}}{{{defaultValueWithParam}}} - {{/vars}} - } + var self = this; + {{#vars}} + /**{{#description}} + * {{{description}}}{{/description}} + * datatype: {{{datatypeWithEnum}}}{{#required}} + * required{{/required}}{{#minimum}} + * minimum: {{minimum}}{{/minimum}}{{#maximum}} + * maximum: {{maximum}}{{/maximum}} + **/ + self.{{name}} = {{#required}}{{name}}{{/required}}{{^required}}{{{defaultValue}}}{{/required}}; + {{/vars}} + self.constructFromObject = function(data) { + if (!data) { + return; + } + {{#vars}} + self.{{name}}{{{defaultValueWithParam}}} + {{/vars}} + } + {{#vars}} /**{{#description}} * get {{{description}}}{{/description}}{{#minimum}} @@ -50,7 +53,7 @@ var {{classname}} = function {{classname}}({{#mandatory}}{{this}}{{^-last}}, {{/ self.{{getter}} = function() { return self.{{name}}; } - + /**{{#description}} * set {{{description}}}{{/description}} * @param {{=<% %>=}}{<% datatypeWithEnum %>}<%={{ }}=%> {{name}} @@ -61,7 +64,7 @@ var {{classname}} = function {{classname}}({{#mandatory}}{{this}}{{^-last}}, {{/ {{/vars}} self.toJson = function () { - return JSON.stringify(self); + return JSON.stringify(self); } } diff --git a/samples/client/petstore/javascript/src/model/Category.js b/samples/client/petstore/javascript/src/model/Category.js index a87f91354a81..ff40497a61a0 100644 --- a/samples/client/petstore/javascript/src/model/Category.js +++ b/samples/client/petstore/javascript/src/model/Category.js @@ -9,35 +9,38 @@ if (typeof module === 'object' && module.exports) { //export module if ( typeof define === "function" && define.amd ) { - define('Category', ['jquery'], - function($) { - return Category; - }); + define('Category', ['jquery'], + function($) { + return Category; + }); } var Category = function Category() { - var self = this; - - /** - * datatype: Integer - **/ - self.id = null; - - /** - * datatype: String - **/ - self.name = null; - + var self = this; - self.constructFromObject = function(data) { - - self.id = data.id; - - self.name = data.name; - - } + /** + * datatype: Integer + **/ + self.id = null; + /** + * datatype: String + **/ + self.name = null; + + + self.constructFromObject = function(data) { + if (!data) { + return; + } + + self.id = data.id; + + self.name = data.name; + + } + /** * @return {Integer} @@ -45,7 +48,7 @@ var Category = function Category() { self.getId = function() { return self.id; } - + /** * @param {Integer} id **/ @@ -59,7 +62,7 @@ var Category = function Category() { self.getName = function() { return self.name; } - + /** * @param {String} name **/ @@ -69,7 +72,7 @@ var Category = function Category() { self.toJson = function () { - return JSON.stringify(self); + return JSON.stringify(self); } } diff --git a/samples/client/petstore/javascript/src/model/Order.js b/samples/client/petstore/javascript/src/model/Order.js index 61120e577d6b..3cf2335b5356 100644 --- a/samples/client/petstore/javascript/src/model/Order.js +++ b/samples/client/petstore/javascript/src/model/Order.js @@ -37,64 +37,67 @@ var StatusEnum = function StatusEnum() { //export module if ( typeof define === "function" && define.amd ) { - define('Order', ['jquery'], - function($) { - return Order; - }); + define('Order', ['jquery'], + function($) { + return Order; + }); } var Order = function Order() { - var self = this; - - /** - * datatype: Integer - **/ - self.id = null; - - /** - * datatype: Integer - **/ - self.petId = null; - - /** - * datatype: Integer - **/ - self.quantity = null; - - /** - * datatype: Date - **/ - self.shipDate = null; - - /** - * Order Status - * datatype: StatusEnum - **/ - self.status = null; - - /** - * datatype: Boolean - **/ - self.complete = null; - + var self = this; - self.constructFromObject = function(data) { - - self.id = data.id; - - self.petId = data.petId; - - self.quantity = data.quantity; - - self.shipDate = data.shipDate; - - self.status = data.status; - - self.complete = data.complete; - - } + /** + * datatype: Integer + **/ + self.id = null; + /** + * datatype: Integer + **/ + self.petId = null; + + /** + * datatype: Integer + **/ + self.quantity = null; + + /** + * datatype: Date + **/ + self.shipDate = null; + + /** + * Order Status + * datatype: StatusEnum + **/ + self.status = null; + + /** + * datatype: Boolean + **/ + self.complete = null; + + + self.constructFromObject = function(data) { + if (!data) { + return; + } + + self.id = data.id; + + self.petId = data.petId; + + self.quantity = data.quantity; + + self.shipDate = data.shipDate; + + self.status = data.status; + + self.complete = data.complete; + + } + /** * @return {Integer} @@ -102,7 +105,7 @@ var Order = function Order() { self.getId = function() { return self.id; } - + /** * @param {Integer} id **/ @@ -116,7 +119,7 @@ var Order = function Order() { self.getPetId = function() { return self.petId; } - + /** * @param {Integer} petId **/ @@ -130,7 +133,7 @@ var Order = function Order() { self.getQuantity = function() { return self.quantity; } - + /** * @param {Integer} quantity **/ @@ -144,7 +147,7 @@ var Order = function Order() { self.getShipDate = function() { return self.shipDate; } - + /** * @param {Date} shipDate **/ @@ -159,7 +162,7 @@ var Order = function Order() { self.getStatus = function() { return self.status; } - + /** * set Order Status * @param {StatusEnum} status @@ -174,7 +177,7 @@ var Order = function Order() { self.getComplete = function() { return self.complete; } - + /** * @param {Boolean} complete **/ @@ -184,7 +187,7 @@ var Order = function Order() { self.toJson = function () { - return JSON.stringify(self); + return JSON.stringify(self); } } diff --git a/samples/client/petstore/javascript/src/model/Pet.js b/samples/client/petstore/javascript/src/model/Pet.js index 7a25a1d5fdd6..25ae2e951c80 100644 --- a/samples/client/petstore/javascript/src/model/Pet.js +++ b/samples/client/petstore/javascript/src/model/Pet.js @@ -39,66 +39,69 @@ var StatusEnum = function StatusEnum() { //export module if ( typeof define === "function" && define.amd ) { - define('Pet', ['jquery', 'Category', 'Array'], - function($, Category, Array) { - return Pet; - }); + define('Pet', ['jquery', 'Category', 'Array'], + function($, Category, Array) { + return Pet; + }); } var Pet = function Pet(photoUrls, name) { - var self = this; - - /** - * datatype: Integer - **/ - self.id = null; - - /** - * datatype: Category - **/ - self.category = new Category(); - - /** - * datatype: String - * required - **/ - self.name = name; - - /** - * datatype: Array - * required - **/ - self.photoUrls = photoUrls; - - /** - * datatype: Array - **/ - self.tags = []; - - /** - * pet status in the store - * datatype: StatusEnum - **/ - self.status = null; - + var self = this; - self.constructFromObject = function(data) { - - self.id = data.id; - - self.category.constructFromObject(data.category); - - self.name = data.name; - - self.photoUrls = new Array(); - - self.tags = new Array(); - - self.status = data.status; - - } + /** + * datatype: Integer + **/ + self.id = null; + /** + * datatype: Category + **/ + self.category = new Category(); + + /** + * datatype: String + * required + **/ + self.name = name; + + /** + * datatype: Array + * required + **/ + self.photoUrls = photoUrls; + + /** + * datatype: Array + **/ + self.tags = []; + + /** + * pet status in the store + * datatype: StatusEnum + **/ + self.status = null; + + + self.constructFromObject = function(data) { + if (!data) { + return; + } + + self.id = data.id; + + self.category.constructFromObject(data.category); + + self.name = data.name; + + self.photoUrls = new Array(); + + self.tags = new Array(); + + self.status = data.status; + + } + /** * @return {Integer} @@ -106,7 +109,7 @@ var Pet = function Pet(photoUrls, name) { self.getId = function() { return self.id; } - + /** * @param {Integer} id **/ @@ -120,7 +123,7 @@ var Pet = function Pet(photoUrls, name) { self.getCategory = function() { return self.category; } - + /** * @param {Category} category **/ @@ -134,7 +137,7 @@ var Pet = function Pet(photoUrls, name) { self.getName = function() { return self.name; } - + /** * @param {String} name **/ @@ -148,7 +151,7 @@ var Pet = function Pet(photoUrls, name) { self.getPhotoUrls = function() { return self.photoUrls; } - + /** * @param {Array} photoUrls **/ @@ -162,7 +165,7 @@ var Pet = function Pet(photoUrls, name) { self.getTags = function() { return self.tags; } - + /** * @param {Array} tags **/ @@ -177,7 +180,7 @@ var Pet = function Pet(photoUrls, name) { self.getStatus = function() { return self.status; } - + /** * set pet status in the store * @param {StatusEnum} status @@ -188,7 +191,7 @@ var Pet = function Pet(photoUrls, name) { self.toJson = function () { - return JSON.stringify(self); + return JSON.stringify(self); } } diff --git a/samples/client/petstore/javascript/src/model/Tag.js b/samples/client/petstore/javascript/src/model/Tag.js index 4801da71e41d..0fa97bd8c78a 100644 --- a/samples/client/petstore/javascript/src/model/Tag.js +++ b/samples/client/petstore/javascript/src/model/Tag.js @@ -9,35 +9,38 @@ if (typeof module === 'object' && module.exports) { //export module if ( typeof define === "function" && define.amd ) { - define('Tag', ['jquery'], - function($) { - return Tag; - }); + define('Tag', ['jquery'], + function($) { + return Tag; + }); } var Tag = function Tag() { - var self = this; - - /** - * datatype: Integer - **/ - self.id = null; - - /** - * datatype: String - **/ - self.name = null; - + var self = this; - self.constructFromObject = function(data) { - - self.id = data.id; - - self.name = data.name; - - } + /** + * datatype: Integer + **/ + self.id = null; + /** + * datatype: String + **/ + self.name = null; + + + self.constructFromObject = function(data) { + if (!data) { + return; + } + + self.id = data.id; + + self.name = data.name; + + } + /** * @return {Integer} @@ -45,7 +48,7 @@ var Tag = function Tag() { self.getId = function() { return self.id; } - + /** * @param {Integer} id **/ @@ -59,7 +62,7 @@ var Tag = function Tag() { self.getName = function() { return self.name; } - + /** * @param {String} name **/ @@ -69,7 +72,7 @@ var Tag = function Tag() { self.toJson = function () { - return JSON.stringify(self); + return JSON.stringify(self); } } diff --git a/samples/client/petstore/javascript/src/model/User.js b/samples/client/petstore/javascript/src/model/User.js index 6d32676a9213..632208a523c8 100644 --- a/samples/client/petstore/javascript/src/model/User.js +++ b/samples/client/petstore/javascript/src/model/User.js @@ -9,78 +9,81 @@ if (typeof module === 'object' && module.exports) { //export module if ( typeof define === "function" && define.amd ) { - define('User', ['jquery'], - function($) { - return User; - }); + define('User', ['jquery'], + function($) { + return User; + }); } var User = function User() { - var self = this; - - /** - * datatype: Integer - **/ - self.id = null; - - /** - * datatype: String - **/ - self.username = null; - - /** - * datatype: String - **/ - self.firstName = null; - - /** - * datatype: String - **/ - self.lastName = null; - - /** - * datatype: String - **/ - self.email = null; - - /** - * datatype: String - **/ - self.password = null; - - /** - * datatype: String - **/ - self.phone = null; - - /** - * User Status - * datatype: Integer - **/ - self.userStatus = null; - + var self = this; - self.constructFromObject = function(data) { - - self.id = data.id; - - self.username = data.username; - - self.firstName = data.firstName; - - self.lastName = data.lastName; - - self.email = data.email; - - self.password = data.password; - - self.phone = data.phone; - - self.userStatus = data.userStatus; - - } + /** + * datatype: Integer + **/ + self.id = null; + /** + * datatype: String + **/ + self.username = null; + + /** + * datatype: String + **/ + self.firstName = null; + + /** + * datatype: String + **/ + self.lastName = null; + + /** + * datatype: String + **/ + self.email = null; + + /** + * datatype: String + **/ + self.password = null; + + /** + * datatype: String + **/ + self.phone = null; + + /** + * User Status + * datatype: Integer + **/ + self.userStatus = null; + + + self.constructFromObject = function(data) { + if (!data) { + return; + } + + self.id = data.id; + + self.username = data.username; + + self.firstName = data.firstName; + + self.lastName = data.lastName; + + self.email = data.email; + + self.password = data.password; + + self.phone = data.phone; + + self.userStatus = data.userStatus; + + } + /** * @return {Integer} @@ -88,7 +91,7 @@ var User = function User() { self.getId = function() { return self.id; } - + /** * @param {Integer} id **/ @@ -102,7 +105,7 @@ var User = function User() { self.getUsername = function() { return self.username; } - + /** * @param {String} username **/ @@ -116,7 +119,7 @@ var User = function User() { self.getFirstName = function() { return self.firstName; } - + /** * @param {String} firstName **/ @@ -130,7 +133,7 @@ var User = function User() { self.getLastName = function() { return self.lastName; } - + /** * @param {String} lastName **/ @@ -144,7 +147,7 @@ var User = function User() { self.getEmail = function() { return self.email; } - + /** * @param {String} email **/ @@ -158,7 +161,7 @@ var User = function User() { self.getPassword = function() { return self.password; } - + /** * @param {String} password **/ @@ -172,7 +175,7 @@ var User = function User() { self.getPhone = function() { return self.phone; } - + /** * @param {String} phone **/ @@ -187,7 +190,7 @@ var User = function User() { self.getUserStatus = function() { return self.userStatus; } - + /** * set User Status * @param {Integer} userStatus @@ -198,7 +201,7 @@ var User = function User() { self.toJson = function () { - return JSON.stringify(self); + return JSON.stringify(self); } } From 1777124e62d45ad30b635ffd39a92337e6f850b8 Mon Sep 17 00:00:00 2001 From: xhh Date: Thu, 17 Dec 2015 21:37:04 +0800 Subject: [PATCH 71/71] Javascript: remove call to `apiClietn.parameterToString` --- .../src/main/resources/Javascript/api.mustache | 4 ++-- samples/client/petstore/javascript/src/api/PetApi.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/swagger-codegen/src/main/resources/Javascript/api.mustache b/modules/swagger-codegen/src/main/resources/Javascript/api.mustache index 0236f6a61be2..9957fc4e2c51 100644 --- a/modules/swagger-codegen/src/main/resources/Javascript/api.mustache +++ b/modules/swagger-codegen/src/main/resources/Javascript/api.mustache @@ -42,7 +42,7 @@ var {{classname}} = function {{classname}}() { } var {{localVariablePrefix}}path = basePath + replaceAll(replaceAll("{{{path}}}", "\\{format\\}","json"){{#pathParams}} -, "\\{" + "{{baseName}}" + "\\}", encodeURIComponent({{localVariablePrefix}}{{{paramName}}}.toString()){{/pathParams}}); +, "\\{" + "{{baseName}}" + "\\}", encodeURIComponent({{{paramName}}}.toString()){{/pathParams}}); var queryParams = {}; var headerParams = {}; @@ -52,7 +52,7 @@ var {{classname}} = function {{classname}}() { queryParams.{{baseName}} = {{paramName}}; {{/queryParams}} {{#headerParams}}if ({{paramName}} != null) - {{localVariablePrefix}}headerParams.put("{{baseName}}", {{localVariablePrefix}}apiClient.parameterToString({{paramName}})); + {{localVariablePrefix}}headerParams.put("{{baseName}}", {{paramName}}); {{/headerParams}} {{#formParams}}if ({{paramName}} != null) {{localVariablePrefix}}formParams.put("{{baseName}}", {{paramName}}); diff --git a/samples/client/petstore/javascript/src/api/PetApi.js b/samples/client/petstore/javascript/src/api/PetApi.js index 3d5eb1dc9e5c..3b6d9c5b4c62 100644 --- a/samples/client/petstore/javascript/src/api/PetApi.js +++ b/samples/client/petstore/javascript/src/api/PetApi.js @@ -401,7 +401,7 @@ var PetApi = function PetApi() { if (apiKey != null) - headerParams.put("api_key", apiClient.parameterToString(apiKey)); + headerParams.put("api_key", apiKey);