From 023a941a15fa6ae2748cd315f8d05ec04fa9e316 Mon Sep 17 00:00:00 2001 From: demonfiddler Date: Thu, 31 Mar 2016 13:50:33 +0100 Subject: [PATCH] Fix for Issue #2471 "JavaScript client code generator emits invalid code for map and array types" --- .../languages/JavascriptClientCodegen.java | 16 +++++++++++ .../resources/Javascript/ApiClient.mustache | 19 +++++++++++++ .../main/resources/Javascript/model.mustache | 27 +++++++++++-------- 3 files changed, 51 insertions(+), 11 deletions(-) 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 0541995b926..b01c9d4cd5c 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 @@ -12,9 +12,12 @@ import io.swagger.codegen.CodegenProperty; import io.swagger.codegen.CodegenType; import io.swagger.codegen.SupportingFile; import io.swagger.codegen.DefaultCodegen; +import io.swagger.models.ArrayModel; +import io.swagger.models.ComposedModel; import io.swagger.models.Info; import io.swagger.models.License; import io.swagger.models.Model; +import io.swagger.models.ModelImpl; import io.swagger.models.Operation; import io.swagger.models.Swagger; import io.swagger.models.properties.ArrayProperty; @@ -705,6 +708,19 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo final CodegenModel parentCodegenModel = super.fromModel(codegenModel.parent, parentModel); codegenModel = JavascriptClientCodegen.reconcileInlineEnums(codegenModel, parentCodegenModel); } + if (model instanceof ArrayModel) { + ArrayModel am = (ArrayModel) model; + if (am.getItems() != null) { + codegenModel.vendorExtensions.put("x-isArray", true); + codegenModel.vendorExtensions.put("x-itemType", getSwaggerType(am.getItems())); + } + } else if (model instanceof ModelImpl) { + ModelImpl mm = (ModelImpl)model; + if (mm.getAdditionalProperties() != null) { + codegenModel.vendorExtensions.put("x-isMap", true); + codegenModel.vendorExtensions.put("x-itemType", getSwaggerType(mm.getAdditionalProperties())); + } + } return codegenModel; } diff --git a/modules/swagger-codegen/src/main/resources/Javascript/ApiClient.mustache b/modules/swagger-codegen/src/main/resources/Javascript/ApiClient.mustache index c470d86d9cd..25a0e5155aa 100644 --- a/modules/swagger-codegen/src/main/resources/Javascript/ApiClient.mustache +++ b/modules/swagger-codegen/src/main/resources/Javascript/ApiClient.mustache @@ -474,6 +474,25 @@ } }; +{{#emitJSDoc}} /** + * Constructs a new map or array model from REST data. + * @param data {Object|Array} The REST data. + * @param obj {Object|Array} The target object or array. + */ +{{/emitJSDoc}} exports.constructFromObject = function(data, obj, itemType) { + if (Array.isArray(data)) { + for (var i = 0; i < data.length; i++) { + if (data.hasOwnProperty(i)) + obj[i] = exports.convertToType(data[i], itemType); + } + } else { + for (var k in data) { + if (data.hasOwnProperty(k)) + result[k] = exports.convertToType(data[k], itemType); + } + } + }; + {{#emitJSDoc}} /** * The default API client implementation. * @type {module:{{#invokerPackage}}{{invokerPackage}}/{{/invokerPackage}}ApiClient} diff --git a/modules/swagger-codegen/src/main/resources/Javascript/model.mustache b/modules/swagger-codegen/src/main/resources/Javascript/model.mustache index 3972fbbda86..37a55ca71f1 100644 --- a/modules/swagger-codegen/src/main/resources/Javascript/model.mustache +++ b/modules/swagger-codegen/src/main/resources/Javascript/model.mustache @@ -26,15 +26,19 @@ * {{description}}{{/description}} * @alias module:{{#invokerPackage}}{{invokerPackage}}/{{/invokerPackage}}{{#modelPackage}}{{modelPackage}}/{{/modelPackage}}{{classname}} * @class{{#useInheritance}}{{#parent}} - * @extends module:{{#invokerPackage}}{{invokerPackage}}/{{/invokerPackage}}{{#modelPackage}}{{modelPackage}}/{{/modelPackage}}{{parent}}{{/parent}}{{#interfaces}} + * @extends {{#parentModel}}module:{{#invokerPackage}}{{invokerPackage}}/{{/invokerPackage}}{{#modelPackage}}{{modelPackage}}/{{/modelPackage}}{{parent}}{{/parentModel}}{{^parentModel}}{{#vendorExtensions.x-isArray}}Array{{/vendorExtensions.x-isArray}}{{#vendorExtensions.x-isMap}}Object{{/vendorExtensions.x-isMap}}{{/parentModel}}{{/parent}}{{#interfaces}} * @implements module:{{#invokerPackage}}{{invokerPackage}}/{{/invokerPackage}}{{#modelPackage}}{{modelPackage}}/{{/modelPackage}}{{.}}{{/interfaces}}{{/useInheritance}}{{#vendorExtensions.x-all-required}} * @param {{.}}{{/vendorExtensions.x-all-required}} - */{{/emitJSDoc}} - var exports = function({{#vendorExtensions.x-all-required}}{{.}}{{^-last}}, {{/-last}}{{/vendorExtensions.x-all-required}}) { -{{#useInheritance}}{{#parentModel}} {{classname}}.call(this{{#vendorExtensions.x-all-required}}, {{.}}{{/vendorExtensions.x-all-required}});{{/parentModel}} -{{#interfaceModels}} {{classname}}.call(this{{#vendorExtensions.x-all-required}}, {{.}}{{/vendorExtensions.x-all-required}}); -{{/interfaceModels}}{{/useInheritance}}{{#vars}}{{#required}} this['{{baseName}}'] = {{name}};{{/required}} -{{/vars}} }; + */ +{{/emitJSDoc}} var exports = function({{#vendorExtensions.x-all-required}}{{.}}{{^-last}}, {{/-last}}{{/vendorExtensions.x-all-required}}) { + var _this = this; +{{#parent}}{{^parentModel}}{{#vendorExtensions.x-isArray}} _this = new Array(); + Object.setPrototypeOf(_this, exports); +{{/vendorExtensions.x-isArray}}{{/parentModel}}{{/parent}}{{#useInheritance}}{{#parent}}{{#parentModel}} {{classname}}.call(_this{{#vendorExtensions.x-all-required}}, {{.}}{{/vendorExtensions.x-all-required}});{{/parentModel}}{{/parent}} +{{#interfaceModels}} {{classname}}.call(_this{{#vendorExtensions.x-all-required}}, {{.}}{{/vendorExtensions.x-all-required}}); +{{/interfaceModels}}{{/useInheritance}}{{#vars}}{{#required}} _this['{{baseName}}'] = {{name}};{{/required}} +{{/vars}}{{#parent}}{{^parentModel}} return _this; +{{/parentModel}}{{/parent}} }; {{#emitJSDoc}} /** * Constructs a {{classname}} from a plain JavaScript object, optionally creating a new instance. @@ -44,9 +48,10 @@ * @return {{=< >=}}{module:<#invokerPackage>/<#modelPackage>/}<={{ }}=> The populated {{classname}} instance. */ {{/emitJSDoc}} exports.constructFromObject = function(data, obj) { - if (data) { {{!// TODO: support polymorphism: discriminator property on data determines class to instantiate.}} + if (data){{! TODO: support polymorphism: discriminator property on data determines class to instantiate.}} { obj = obj || new exports(); -{{#useInheritance}}{{#parent}} {{.}}.constructFromObject(data, obj);{{/parent}} +{{#parent}}{{^parentModel}} ApiClient.constructFromObject(data, obj, {{vendorExtensions.x-itemType}}); +{{/parentModel}}{{/parent}}{{#useInheritance}}{{#parentModel}}{{#parent}} {{parent}}.constructFromObject(data, obj);{{/parent}}{{/parentModel}} {{#interfaces}} {{.}}.constructFromObject(data, obj); {{/interfaces}}{{/useInheritance}}{{#vars}} if (data.hasOwnProperty('{{baseName}}')) { obj['{{baseName}}']{{{defaultValueWithParam}}} @@ -54,10 +59,10 @@ {{/vars}} } return obj; } -{{#useInheritance}}{{#parent}} +{{#useInheritance}}{{#parentModel}}{{#parent}} exports.prototype = Object.create({{parent}}.prototype); exports.prototype.constructor = exports; -{{/parent}}{{/useInheritance}} +{{/parent}}{{/parentModel}}{{/useInheritance}} {{#vars}}{{#emitJSDoc}} /**{{#description}} * {{{description}}}{{/description}}