From 57aa6d01d23aa58b128d279f96a564cc6d5b7ee3 Mon Sep 17 00:00:00 2001 From: Jakub Malek Date: Tue, 24 May 2016 10:14:22 +0200 Subject: [PATCH] NancyFx: - Using virtual interface implementation in AbstractService - Fixed namespace for module classes - Using Parameters utility for parsing parameters in NancyModule - Excluding obj folder from csproj --- .../languages/NancyFXServerCodegen.java | 87 +++++------- .../main/resources/nancyfx/Project.mustache | 2 +- .../src/main/resources/nancyfx/api.mustache | 11 +- ...xtensions.mustache => parameters.mustache} | 125 ++++++------------ 4 files changed, 83 insertions(+), 142 deletions(-) rename modules/swagger-codegen/src/main/resources/nancyfx/{requestExtensions.mustache => parameters.mustache} (78%) diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/NancyFXServerCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/NancyFXServerCodegen.java index 37f3b66cdf36..3bd66f560da9 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/NancyFXServerCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/NancyFXServerCodegen.java @@ -1,6 +1,5 @@ package io.swagger.codegen.languages; -import io.swagger.codegen.CodegenConstants; import io.swagger.codegen.CodegenOperation; import io.swagger.codegen.CodegenType; import io.swagger.codegen.SupportingFile; @@ -8,66 +7,45 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; -import java.util.Arrays; + +import static io.swagger.codegen.CodegenConstants.*; +import static io.swagger.codegen.CodegenType.SERVER; +import static java.util.Arrays.asList; +import static java.util.UUID.randomUUID; public class NancyFXServerCodegen extends AbstractCSharpCodegen { + private static final Logger log = LoggerFactory.getLogger(NancyFXServerCodegen.class); - protected String packageGuid = "{" + java.util.UUID.randomUUID().toString().toUpperCase() + "}"; - - @SuppressWarnings("hiding") - protected Logger LOGGER = LoggerFactory.getLogger(NancyFXServerCodegen.class); + private final String packageGuid = "{" + randomUUID().toString().toUpperCase() + "}"; public NancyFXServerCodegen() { - outputFolder = "generated-code" + File.separator + this.getName(); - + outputFolder = "generated-code" + File.separator + getName(); modelTemplateFiles.put("model.mustache", ".cs"); apiTemplateFiles.put("api.mustache", ".cs"); // contextually reserved words setReservedWordsLowerCase( - Arrays.asList("var", "async", "await", "dynamic", "yield") + asList("var", "async", "await", "dynamic", "yield") ); cliOptions.clear(); // CLI options - addOption(CodegenConstants.PACKAGE_NAME, - "C# package name (convention: Title.Case).", - this.packageName); - - addOption(CodegenConstants.PACKAGE_VERSION, - "C# package version.", - this.packageVersion); - - addOption(CodegenConstants.SOURCE_FOLDER, - CodegenConstants.SOURCE_FOLDER_DESC, - sourceFolder); + addOption(PACKAGE_NAME, "C# package name (convention: Title.Case).", packageName); + addOption(PACKAGE_VERSION, "C# package version.", packageVersion); + addOption(SOURCE_FOLDER, SOURCE_FOLDER_DESC, sourceFolder); // CLI Switches - addSwitch(CodegenConstants.SORT_PARAMS_BY_REQUIRED_FLAG, - CodegenConstants.SORT_PARAMS_BY_REQUIRED_FLAG_DESC, - this.sortParamsByRequiredFlag); - - addSwitch(CodegenConstants.OPTIONAL_PROJECT_FILE, - CodegenConstants.OPTIONAL_PROJECT_FILE_DESC, - this.optionalProjectFileFlag); - - addSwitch(CodegenConstants.USE_DATETIME_OFFSET, - CodegenConstants.USE_DATETIME_OFFSET_DESC, - this.useDateTimeOffsetFlag); - - addSwitch(CodegenConstants.USE_COLLECTION, - CodegenConstants.USE_COLLECTION_DESC, - this.useCollection); - - addSwitch(CodegenConstants.RETURN_ICOLLECTION, - CodegenConstants.RETURN_ICOLLECTION_DESC, - this.returnICollection); + addSwitch(SORT_PARAMS_BY_REQUIRED_FLAG, SORT_PARAMS_BY_REQUIRED_FLAG_DESC, sortParamsByRequiredFlag); + addSwitch(OPTIONAL_PROJECT_FILE, OPTIONAL_PROJECT_FILE_DESC, optionalProjectFileFlag); + addSwitch(USE_DATETIME_OFFSET, USE_DATETIME_OFFSET_DESC, useDateTimeOffsetFlag); + addSwitch(USE_COLLECTION, USE_COLLECTION_DESC, useCollection); + addSwitch(RETURN_ICOLLECTION, RETURN_ICOLLECTION_DESC, returnICollection); } @Override public CodegenType getTag() { - return CodegenType.SERVER; + return SERVER; } @Override @@ -84,10 +62,10 @@ public class NancyFXServerCodegen extends AbstractCSharpCodegen { public void processOpts() { super.processOpts(); - apiPackage = packageName + ".Module"; - modelPackage = packageName + ".Model"; + apiPackage = packageName + ".Modules"; + modelPackage = packageName + ".Models"; - supportingFiles.add(new SupportingFile("RequestExtensions.mustache", sourceFolder(), "RequestExtensions.cs")); + supportingFiles.add(new SupportingFile("parameters.mustache", sourceFile("Utils"), "Parameters.cs")); supportingFiles.add(new SupportingFile("packages.config.mustache", sourceFolder(), "packages.config")); if (optionalProjectFileFlag) { @@ -101,14 +79,18 @@ public class NancyFXServerCodegen extends AbstractCSharpCodegen { return "src" + File.separator + packageName; } + private String sourceFile(final String fileName) { + return sourceFolder() + File.separator + fileName; + } + @Override public String apiFileFolder() { - return outputFolder + File.separator + sourceFolder() + File.separator + "Module"; + return outputFolder + File.separator + sourceFolder() + File.separator + "Modules"; } @Override public String modelFileFolder() { - return outputFolder + File.separator + sourceFolder() + File.separator + "Model"; + return outputFolder + File.separator + sourceFolder() + File.separator + "Models"; } @Override @@ -120,7 +102,7 @@ public class NancyFXServerCodegen extends AbstractCSharpCodegen { String original = operation.path; operation.path = operation.path.replace("?", "/"); if (!original.equals(operation.path)) { - LOGGER.warn("Normalized " + original + " to " + operation.path + ". Please verify generated source."); + log.warn("Normalized " + original + " to " + operation.path + ". Please verify generated source."); } } @@ -130,14 +112,11 @@ public class NancyFXServerCodegen extends AbstractCSharpCodegen { @Override public String toEnumVarName(String name, String datatype) { - String enumName = sanitizeName(name); - - enumName = enumName.replaceFirst("^_", ""); - enumName = enumName.replaceFirst("_$", ""); - - enumName = camelize(enumName); - - LOGGER.info("toEnumVarName = " + enumName); + final String enumName = camelize( + sanitizeName(name) + .replaceFirst("^_", "") + .replaceFirst("_$", "")); + log.info("toEnumVarName = " + enumName); if (enumName.matches("\\d.*")) { // starts with number return "_" + enumName; diff --git a/modules/swagger-codegen/src/main/resources/nancyfx/Project.mustache b/modules/swagger-codegen/src/main/resources/nancyfx/Project.mustache index ae16f386e984..8d1f652022da 100644 --- a/modules/swagger-codegen/src/main/resources/nancyfx/Project.mustache +++ b/modules/swagger-codegen/src/main/resources/nancyfx/Project.mustache @@ -83,7 +83,7 @@ - + diff --git a/modules/swagger-codegen/src/main/resources/nancyfx/api.mustache b/modules/swagger-codegen/src/main/resources/nancyfx/api.mustache index 9cba02edc3a5..537f59000941 100644 --- a/modules/swagger-codegen/src/main/resources/nancyfx/api.mustache +++ b/modules/swagger-codegen/src/main/resources/nancyfx/api.mustache @@ -4,8 +4,9 @@ using Nancy.ModelBinding; using System.Collections.Generic; using Sharpility.Base; using {{packageName}}.Models; +using {{packageName}}.Utils; -namespace {{packageName}}.Api +namespace {{packageName}}.Modules { {{#operations}}{{#operation}}{{#allParams}}{{#isEnum}}{{>innerApiEnum}}{{/isEnum}}{{/allParams}}{{/operation}} public sealed class {{classname}}Module : NancyModule { @@ -14,11 +15,9 @@ namespace {{packageName}}.Api { {{#operation}} {{httpMethod}}["{{path}}"] = parameters => { - {{#allParams}}{{#isBodyParam}} - var {{paramName}} = this.Bind<{{&dataType}}>(); - {{/isBodyParam}}{{^isBodyParam}}{{#isEnum}}{{>innerApiEnumName}}{{/isEnum}}{{^isEnum}}{{&dataType}}{{/isEnum}} {{paramName}} = parameters.{{paramName}};{{#hasMore}} + {{#allParams}}{{#isBodyParam}}var {{paramName}} = this.Bind<{{&dataType}}>();{{/isBodyParam}}{{^isBodyParam}}{{#isEnum}}{{>innerApiEnumName}}{{/isEnum}}{{^isEnum}}var{{/isEnum}} {{paramName}} = Parameters.ValueOf<{{&dataType}}>(parameters, "{{paramName}}");{{#hasMore}} {{/hasMore}}{{/isBodyParam}}{{/allParams}}{{#allParams}}{{#required}} - Preconditions.IsNotNull({{paramName}}, "Missing the required parameter '{{paramName}}' when calling {{operationId}}"); + Preconditions.IsNotNull({{paramName}}, "Required parameter: '{{paramName}}' is missing at '{{operationId}}'"); {{/required}}{{/allParams}} {{#returnType}}return {{/returnType}}service.{{operationId}}(Request{{#allParams.0}}, {{/allParams.0}}{{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}});{{^returnType}} return new Response { ContentType = "{{produces.0.mediaType}}"};{{/returnType}} @@ -36,7 +35,7 @@ namespace {{packageName}}.Api public abstract class Abstract{{classname}}Service: {{classname}}Service { - {{#operation}}public {{#returnType}}{{&returnType}}{{/returnType}}{{^returnType}}void{{/returnType}} {{operationId}}(Request request{{#allParams.0}}, {{/allParams.0}}{{>paramsList}}) + {{#operation}}public virtual {{#returnType}}{{&returnType}}{{/returnType}}{{^returnType}}void{{/returnType}} {{operationId}}(Request request{{#allParams.0}}, {{/allParams.0}}{{>paramsList}}) { {{#returnType}}return {{/returnType}}{{operationId}}({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}); }{{#hasMore}} diff --git a/modules/swagger-codegen/src/main/resources/nancyfx/requestExtensions.mustache b/modules/swagger-codegen/src/main/resources/nancyfx/parameters.mustache similarity index 78% rename from modules/swagger-codegen/src/main/resources/nancyfx/requestExtensions.mustache rename to modules/swagger-codegen/src/main/resources/nancyfx/parameters.mustache index 3725af752304..a0b8e326cc8f 100644 --- a/modules/swagger-codegen/src/main/resources/nancyfx/requestExtensions.mustache +++ b/modules/swagger-codegen/src/main/resources/nancyfx/parameters.mustache @@ -1,3 +1,4 @@ + using System; using System.Collections.Generic; using System.Collections.Immutable; @@ -7,91 +8,52 @@ using Sharpility.Base; using Sharpility.Extensions; using Sharpility.Util; -namespace {{packageName}} +namespace {{packageName}}.Utils { - internal static class RequestExtensions + internal static class Parameters { private static readonly IDictionary> Parsers = CreateParsers(); - internal static TParam QueryParam(this Request source, string name) + internal static TValue ValueOf(dynamic parameters, string name) { - return QueryParam(source, name, default(TParam), useDefault: false); - } - - internal static TParam QueryParam(this Request source, string name, TParam defaultValue) - { - return QueryParam(source, name, defaultValue, useDefault: true); - } - - internal static THeader HeaderValue(this Request source, string name) - { - return HeaderValue(source, name, default(THeader), useDefault: false); - } - - internal static THeader HeaderValue(this Request source, string name, THeader defaultValue) - { - return HeaderValue(source, name, defaultValue, useDefault: true); - } - - internal static TPathParam PathParam(dynamic parameters, string name) - { - return PathParam(parameters, name, default(TPathParam), useDefault: false); - } - - internal static TPathParam PathParam(dynamic parameters, string name, TPathParam defaultValue) - { - return PathParam(parameters, name, defaultValue, useDefault: true); - } - - private static TParam QueryParam(Request source, string name, TParam defaultValue, bool useDefault) - { - Preconditions.IsNotNull(source, () => new NullReferenceException("source")); - var valueType = typeof(TParam); - var parser = Parsers.GetIfPresent(valueType); - if (parser == null) - { - return TryParseUsingDynamic(source.Query, name, defaultValue); - } - string value = source.Query[name]; - return ValueOf(name, value, defaultValue, useDefault, parser); - } - - private static THeader HeaderValue(Request source, string name, THeader defaultValue, bool useDefault) - { - Preconditions.IsNotNull(source, () => new NullReferenceException("source")); - var valueType = typeof(THeader); - var values = source.Headers[name]; - var parser = Parsers.GetIfPresent(valueType); - var value = values != null ? string.Join(",", values) : null; - Preconditions.IsNotNull(parser, () => new InvalidOperationException( - Strings.Format("Header: '{0}' value: '{1}' could not be parsed. Expected type: '{2}' is not supported", - name, value, valueType))); - return ValueOf(name, value, defaultValue, useDefault, parser); - - } - - private static TPathParam PathParam(dynamic parameters, string name, TPathParam defaultValue, bool useDefault) - { - var valueType = typeof(TPathParam); - var parser = Parsers.GetIfPresent(valueType); - if (parser == null) - { - return TryParseUsingDynamic(parameters, name, defaultValue); - } + var valueType = typeof (TValue); + var isNullable = default(TValue) == null; string value = parameters[name]; - return ValueOf(name, value, defaultValue, useDefault, parser); + Preconditions.Evaluate(!string.IsNullOrEmpty(value) || isNullable, string.Format("Required parameter: '{0}' is missing", name)); + if (valueType.IsEnum) + { + return EnumValueOf(name, value); + } + return ValueOf(parameters, name, value, valueType); } - private static TValue ValueOf(string name, string value, TValue defaultValue, bool useDefault, Func parser) + private static TValue EnumValueOf(string name, string value) { - var valueType = typeof(TValue); - var nullable = default(TValue) == null; - if (string.IsNullOrEmpty(value)) + var values = Enum.GetValues(typeof(TValue)); + foreach (var entry in values) { - Preconditions.Evaluate(nullable || (defaultValue != null && useDefault), () => - new ArgumentException(Strings.Format("Query: '{0}' value was not specified", name))); - return defaultValue; + if (entry.ToString().EqualsIgnoreCases(value) + || ((int) entry).ToString().EqualsIgnoreCases(value)) + { + return (TValue) entry; + } } + throw new ArgumentException(string.Format("Parameter: '{0}' value: '{1}' is not supported. Expected one of: {2}", + name, value, value.ToComparable())); + } + + private static TValue ValueOf(dynamic parameters, string name, string value, Type valueType) + { + var parser = Parsers.GetIfPresent(valueType); + if (parser != null) + { + return ParseValueUsing(name, value, valueType, parser); + } + return DynamicValueOf(parameters, name); + } + + private static TValue ParseValueUsing(string name, string value, Type valueType, Func parser) + { var result = parser(Parameter.Of(name, value)); try { @@ -99,21 +61,22 @@ namespace {{packageName}} } catch (InvalidCastException) { - throw new InvalidOperationException(Strings.Format( - "Unexpected result type: '{0}' for query: '{1}' expected: '{2}'", - result.GetType(), name, valueType)); + throw new InvalidOperationException( + string.Format("Could not parse parameter: '{0}' with value: '{1}'. " + + "Received: '{2}', expected: '{3}'.", + name, value, result.GetType(), valueType)); } } - private static TValue TryParseUsingDynamic(dynamic parameters, string name, TValue defaultValue) + private static TValue DynamicValueOf(dynamic parameters, string name) { string value = parameters[name]; try { TValue result = parameters[name]; - return result != null ? result : defaultValue; + return result; } - catch (Exception) + catch (InvalidCastException) { throw new InvalidOperationException(Strings.Format("Parameter: '{0}' value: '{1}' could not be parsed. " + "Expected type: '{2}' is not supported", @@ -346,7 +309,7 @@ namespace {{packageName}} private static ArgumentException ParameterOutOfRange(Parameter parameter, Type type) { - return new ArgumentException(Strings.Format("Query: '{0}' value: '{1}' is out of range for: '{2}'", + return new ArgumentException(Strings.Format("Query: '{0}' value: '{1}' is out of range for: '{2}'", parameter.Name, parameter.Value, type)); }