- Using virtual interface implementation in AbstractService
 - Fixed namespace for module classes
 - Using Parameters utility for parsing parameters in NancyModule
 - Excluding obj folder from csproj
This commit is contained in:
Jakub Malek
2016-05-24 10:14:22 +02:00
committed by Jakub Malek
parent 04af1cf2a7
commit 57aa6d01d2
4 changed files with 83 additions and 142 deletions

View File

@@ -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;

View File

@@ -83,7 +83,7 @@
<Reference Include="System.Xml"/>
</ItemGroup>
<ItemGroup>
<Compile Include="**\*.cs"/>
<Compile Include="**\*.cs" Exclude="obj\**"/>
</ItemGroup>
<ItemGroup>
<Content Include="packages.config"/>

View File

@@ -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}}

View File

@@ -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<Type, Func<Parameter, object>> Parsers = CreateParsers();
internal static TParam QueryParam<TParam>(this Request source, string name)
internal static TValue ValueOf<TValue>(dynamic parameters, string name)
{
return QueryParam(source, name, default(TParam), useDefault: false);
}
internal static TParam QueryParam<TParam>(this Request source, string name, TParam defaultValue)
{
return QueryParam(source, name, defaultValue, useDefault: true);
}
internal static THeader HeaderValue<THeader>(this Request source, string name)
{
return HeaderValue(source, name, default(THeader), useDefault: false);
}
internal static THeader HeaderValue<THeader>(this Request source, string name, THeader defaultValue)
{
return HeaderValue(source, name, defaultValue, useDefault: true);
}
internal static TPathParam PathParam<TPathParam>(dynamic parameters, string name)
{
return PathParam(parameters, name, default(TPathParam), useDefault: false);
}
internal static TPathParam PathParam<TPathParam>(dynamic parameters, string name, TPathParam defaultValue)
{
return PathParam(parameters, name, defaultValue, useDefault: true);
}
private static TParam QueryParam<TParam>(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<THeader>(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<TPathParam>(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<TValue>(name, value);
}
return ValueOf<TValue>(parameters, name, value, valueType);
}
private static TValue ValueOf<TValue>(string name, string value, TValue defaultValue, bool useDefault, Func<Parameter, object> parser)
private static TValue EnumValueOf<TValue>(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<TValue>(dynamic parameters, string name, string value, Type valueType)
{
var parser = Parsers.GetIfPresent(valueType);
if (parser != null)
{
return ParseValueUsing<TValue>(name, value, valueType, parser);
}
return DynamicValueOf<TValue>(parameters, name);
}
private static TValue ParseValueUsing<TValue>(string name, string value, Type valueType, Func<Parameter, object> 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<TValue>(dynamic parameters, string name, TValue defaultValue)
private static TValue DynamicValueOf<TValue>(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));
}