Merge pull request #10 from marek-stoj/master

added support for C# (thanks @marek-stoj)
This commit is contained in:
fehguy 2012-05-14 08:50:14 -07:00
commit c0aecff3dc
20 changed files with 1296 additions and 7 deletions

4
.gitignore vendored
View File

@ -11,3 +11,7 @@ build/*
generated-files/*
*.swp
*.swo
/target
/generated-files
/nbactions.xml

View File

@ -56,6 +56,11 @@ mvn package
./bin/generate-python-lib.sh http://petstore.swagger.wordnik.com/api "" "client" "generated-files"
</pre>
#### C&#35;
<pre>
bin\generate-csharp-lib.cmd http://petstore.swagger.wordnik.com/api "your_api_key" "PetStore" "generated-files"
</pre>
The main class for the generator is at src/main/java/com/wordnik/swagger/codegen/config/java/JavaLibCodeGen.java
The code-gen uses the antlr string template library for generating the output files, please look at

View File

@ -0,0 +1,14 @@
@echo off
if "%1"=="" goto DISPLAY_USAGE
if "%2"=="" goto DISPLAY_USAGE
if "%3"=="" goto DISPLAY_USAGE
if "%4"=="" goto DISPLAY_USAGE
java -cp "target\*;target\lib\*" com.wordnik.swagger.codegen.config.csharp.CSharpLibCodeGen %*
goto END
:DISPLAY_USAGE
echo Usage: %0 apiUrl apiKey namespace outputDir
:END

View File

@ -0,0 +1,32 @@
/**
* Copyright 2011 Wordnik, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace SwaggerRuntime.Attributes
{
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Method)]
public class AllowableValuesAttribute : Attribute
{
private string _value = "";
public string Value
{
get { return _value; }
set { _value = value; }
}
}
}

View File

@ -0,0 +1,32 @@
/**
* Copyright 2011 Wordnik, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace SwaggerRuntime.Attributes
{
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Method)]
public class MethodArgumentNamesAttribute : Attribute
{
private string _value = "";
public string Value
{
get { return _value; }
set { _value = value; }
}
}
}

View File

@ -0,0 +1,25 @@
/**
* Copyright 2011 Wordnik, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace SwaggerRuntime.Attributes
{
[AttributeUsage(AttributeTargets.Property)]
public class RequiredAttribute : Attribute
{
}
}

View File

@ -0,0 +1,161 @@
/**
* Copyright 2011 Wordnik, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Web;
using Newtonsoft.Json;
using SwaggerRuntime.Exceptions;
namespace SwaggerRuntime.Common
{
public abstract class ApiBase
{
private readonly string _apiBaseUrl;
private readonly ISecurityHandler _securityHandler;
protected ApiBase(string apiBaseUrl, ISecurityHandler securityHandler)
{
if (string.IsNullOrEmpty(apiBaseUrl))
{
throw new ArgumentException("Argument can't be null nor empty.", "apiBaseUrl");
}
if (securityHandler == null)
{
throw new ArgumentNullException("securityHandler");
}
_apiBaseUrl = apiBaseUrl;
_securityHandler = securityHandler;
}
protected string InvokeApi(string resourceUrl, string method, IDictionary<string, string> queryParams, Object postData, IDictionary<string, string> headerParams)
{
string absoluteResourceUrl = _apiBaseUrl + resourceUrl;
if (queryParams.Count > 0)
{
bool isFirst = true;
foreach (string queryParamName in queryParams.Keys)
{
absoluteResourceUrl += isFirst ? "?" : "&";
isFirst = false;
absoluteResourceUrl += queryParamName + "=" + EncodeUrl(queryParams[queryParamName]);
}
}
var headers = new Dictionary<string, string>();
_securityHandler.PopulateSecurityInfo(absoluteResourceUrl, headers);
var request = (HttpWebRequest)WebRequest.Create(absoluteResourceUrl);
request.Method = method;
foreach (KeyValuePair<string, string> headerKvp in headers)
{
request.Headers[headerKvp.Key] = headerKvp.Value;
}
if (headerParams != null)
{
foreach (KeyValuePair<string, string> headerKvp in headerParams)
{
request.Headers[headerKvp.Key] = headerKvp.Value;
}
}
using (var response = (HttpWebResponse)request.GetResponse())
using (Stream responseStream = response.GetResponseStream())
{
if (responseStream == null)
{
throw new IOException("Couldn't get response stream.");
}
if (response.StatusCode != HttpStatusCode.OK)
{
throw new ApiException((int)response.StatusCode);
}
using (var sr = new StreamReader(responseStream))
{
return sr.ReadToEnd();
}
}
}
protected T Deserialize<T>(string response)
{
var jsonSerializer = new JsonSerializer();
using (var sr = new StringReader(response))
using (var jtr = new JsonTextReader(sr))
{
return jsonSerializer.Deserialize<T>(jtr);
}
}
protected string Serialize(object input)
{
var jsonSerializer = new JsonSerializer();
var sb = new StringBuilder();
using (var sw = new StringWriter(sb))
{
jsonSerializer.Serialize(sw, input);
}
return sb.ToString();
}
protected string ToPathValue(string value)
{
return EncodeUrl(value ?? "");
}
protected string ToPathValue(IEnumerable<object> objects)
{
StringBuilder outSb = new StringBuilder();
foreach (object obj in objects)
{
outSb.Append(obj.ToString());
outSb.Append(",");
}
string output = outSb.ToString();
if (output.IndexOf(",") != -1)
{
output = output.Substring(0, output.LastIndexOf(","));
}
return EncodeUrl(output);
}
protected string EncodeUrl(string value)
{
return HttpUtility.UrlEncode(value);
}
}
}

View File

@ -0,0 +1,45 @@
/**
* Copyright 2011 Wordnik, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
namespace SwaggerRuntime.Common
{
public class ApiKeyAuthTokenBasedSecurityHandler : ISecurityHandler
{
private readonly string _apiKey = "";
public ApiKeyAuthTokenBasedSecurityHandler(string apiKey)
{
if (string.IsNullOrEmpty(apiKey))
{
throw new ArgumentException("Argument can't be null nor empty.", "apiKey");
}
_apiKey = apiKey;
}
#region ISecurityHandler members
public void PopulateSecurityInfo(string resourceURL, IDictionary<string, string> httpHeaders)
{
httpHeaders.Add("api_key", _apiKey);
}
#endregion
}
}

View File

@ -0,0 +1,43 @@
/**
* Copyright 2011 Wordnik, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System.Collections.Generic;
namespace SwaggerRuntime.Common
{
/// <summary>
/// Provide methods that are responsible for handling security aspect while communicating with the backend server.
///
/// Example: For some cases API key may need to be passed in the headers for all server communication and some times
/// user authentication token may need to be passed along with api key.
///
/// Implementers of this class are responsible for handling storing information related to secutiry and sending it
/// along with all API calls.
/// </summary>
public interface ISecurityHandler
{
/// <summary>
/// Populate the security infomration in http headers map and/or reqsource URL.
///
/// Values populated in the http headers map will be set as http headers while making the server communication.
///
/// Depending on the usecase requried information can be added to either of them or both.
/// </summary>
/// <param name="resourceURL"></param>
/// <param name="httpHeaders"></param>
void PopulateSecurityInfo(string resourceURL, IDictionary<string, string> httpHeaders);
}
}

View File

@ -0,0 +1,36 @@
/**
* Copyright 2011 Wordnik, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace SwaggerRuntime.Exceptions
{
/// <summary>
/// An exception that is thrown if there are any issues while invoking the API.
/// </summary>
[Serializable]
public class ApiException : Exception
{
public ApiException(int httpStatusCode)
: base(string.Format("Api exception ({0}).", httpStatusCode))
{
HttpStatusCode = httpStatusCode;
}
public int HttpStatusCode { get; private set; }
}
}

View File

@ -0,0 +1,29 @@
/**
* Copyright 2011 Wordnik, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace $packageName$
{
/// <summary>
/// $enum.description; format="xml-safe"$
/// </summary>
/// <remarks>
/// NOTE: This class is auto generated by the swagger code generator program. Do not edit the class manually.
/// </remarks>
public enum $className$
{
$values: { value | $value.name$ };separator=",\r\n"$
}
}

View File

@ -0,0 +1,47 @@
/**
* Copyright 2011 Wordnik, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using SwaggerRuntime.Attributes;
$imports:{ import |
using $import$;
}$
namespace $packageName$
{
/// <summary>
/// $model.description; format="xml-safe"$
/// </summary>
/// <remarks>
/// NOTE: This class is auto generated by the swagger code generator program. Do not edit the class manually.
/// </remarks>
public class $className$ : $extends$
{
$fields:{ field |
/// <summary>
/// $field.description; format="xml-safe"$
/// </summary>
$if(field.required)$
[Required]
$endif$
$if(field.allowableValues)$
[AllowableValues(Value="$field.allowedValuesString$")]
$endif$
public $field.fieldDefinition.returnType$ $field.fieldDefinition.NameForMethod$ { get; set; }
}$
}
}

View File

@ -0,0 +1,136 @@
/**
* Copyright 2011 Wordnik, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.IO;
using $modelPackageName$;
using SwaggerRuntime.Attributes;
using SwaggerRuntime.Common;
using SwaggerRuntime.Exceptions;
$imports:{ import |
import $import$;
}$
namespace $packageName$
{
/// <remarks>
/// NOTE: This class is auto generated by the swagger code generator program. Do not edit the class manually.
/// </remarks>
public class $resource$ : $extends$
{
public $resource$(string apiBaseUrl, ISecurityHandler securityHandler)
: base(apiBaseUrl, securityHandler)
{
}
$methods:{ method |
/// <summary>
/// $method.title; format="xml-safe"$
$if(method.description)$
/// $method.description; format="xml-safe"$
$endif$</summary>
$method.arguments:{ argument | /// <param name="$argument.name; format="xml-safe"$">
/// $argument.description; format="xml-safe"$
$if(argument.allowedValues)$
/// Allowed values are - $argument.allowedValues; format="xml-safe"$
$endif$
/// </param> }$
$if(!method.responseVoid)$
/// <returns>
/// <see cref="$method.returnClassName; format="xml-safe"$">$method.returnValue; format="xml-safe"$</see>
/// </returns>
$endif$
/// <exception cref="ApiException">$method.exceptionDescription; format="xml-safe"$</exception>
$if(method.hasArguments)$
[MethodArgumentNames(Value = "$method.argumentNames; separator=", "$")]
$endif$
public $method.returnValue$ $method.name$($method.argumentDefinitions; separator=", "$)
{
// parse inputs
string resourcePath = "$method.resourcePath$";
resourcePath = resourcePath.Replace("{format}","json");
string method = "$method.methodType$";
var queryParams = new Dictionary<string, string>();
var headerParams = new Dictionary<string, string>();
$if(!method.inputModel)$
$method.queryParameters:{ argument |
if( $argument.name$ != null) {
queryParams.Add("$argument.name$", ToPathValue($argument.name$));
}
}$
$method.pathParameters:{ argument |
if ($argument.name$ != null)
{
resourcePath = resourcePath.Replace("{$argument.name$}", ToPathValue($argument.name$));
}
}$
$method.headerParameters:{ argument |
if ($argument.name$ != null)
{
headerParams.Add("$argument.name$", ToPathValue($argument.name$));
}
}$
$endif$
$if(method.inputModel)$
$method.queryParameters:{ argument |
if ($argument.inputModelClassArgument$ != null && $argument.methodNameFromModelClass$ != null)
{
queryParams.Add("$argument.name$", ToPathValue($argument.methodNameFromModelClass$));
}
}$
$method.pathParameters:{ argument |
if ($argument.inputModelClassArgument$ != null && $argument.methodNameFromModelClass$ != null)
{
resourcePath = resourcePath.Replace("{$argument.name$}", ToPathValue($argument.methodNameFromModelClass$));
}
}$
$method.headerParameters:{ argument |
if ($argument.inputModelClassArgument$ != null && $argument.methodNameFromModelClass$ != null)
{
headerParams.Add("$argument.name$", ToPathValue($argument.methodNameFromModelClass$));
}
}$
$endif$
// make the API Call
$if(method.postObject)$ $if(!method.responseVoid)$string response = $endif$InvokeApi(resourcePath, method, queryParams, postData, headerParams);$endif$
$if(!method.postObject)$ $if(!method.responseVoid)$string response = $endif$InvokeApi(resourcePath, method, queryParams, null, headerParams);$endif$
$if(!method.responseVoid)$
if (string.IsNullOrEmpty(response))
{
return null;
}
$if(!method.returnValueList)$
// create output objects if the response has more than one object
$method.returnValue$ responseObject = Deserialize<$method.returnClassName$>(response);
return responseObject;
$endif$
$if(method.returnValueList)$
return Deserialize<List<$method.returnClassName$>>(response);
$endif$
$endif$
}
}$
}
}

View File

@ -0,0 +1,32 @@
/**
* Copyright 2011 Wordnik, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace $packageName$
{
/// <summary>
/// Maintains the compatible server version against which the drive is written.
/// </summary>
/// <remarks>
/// NOTE: This class is auto generated by the swagger code generator program. Do not edit the class manually.
/// </remarks>
public static class VersionChecker
{
/// <summary>
/// The version against which the library code was written.
/// </summary>
public const string CompatibleVersion = "$apiVersion$";
}
}

View File

@ -74,13 +74,18 @@ public class LibraryCodeGenerator {
this.setLanguageConfig( initializeLangConfig(readLanguageConfiguration(configPath, mapper, configFile)) );
}
public LibraryCodeGenerator(String apiServerURL, String apiKey, String modelPackageName, String apiPackageName,
String classOutputDir, String modelDirectory, String resourceDirectory, String libraryHome){
initialize(apiServerURL, apiKey, modelPackageName, apiPackageName, classOutputDir, modelDirectory, resourceDirectory, libraryHome);
}
public LibraryCodeGenerator(String apiServerURL, String apiKey, String modelPackageName, String apiPackageName,
String classOutputDir, String libraryHome){
initialize(apiServerURL, apiKey, modelPackageName, apiPackageName, classOutputDir, libraryHome);
this(apiServerURL, apiKey, modelPackageName, apiPackageName, classOutputDir, "model", "api", libraryHome);
}
protected void initialize(String apiServerURL, String apiKey, String modelPackageName, String apiPackageName,
String classOutputDir, String libraryHome){
String classOutputDir, String modelDirectory, String resourceDirectory, String libraryHome){
final ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
ApiConfiguration aApiConfiguration = new ApiConfiguration();
@ -92,12 +97,16 @@ public class LibraryCodeGenerator {
CodeGenRulesProvider codeGenRules = new CodeGenRulesProvider();
this.setCodeGenRulesProvider(codeGenRules);
LanguageConfiguration aLanguageConfiguration = new LanguageConfiguration();
aLanguageConfiguration.setOutputDirectory(classOutputDir);
aLanguageConfiguration.setOutputDirectory(classOutputDir, modelDirectory, resourceDirectory);
aLanguageConfiguration.setLibraryHome(libraryHome);
initializeLangConfig(aLanguageConfiguration);
this.setLanguageConfig(aLanguageConfiguration);
}
protected void initialize(String apiServerURL, String apiKey, String modelPackageName, String apiPackageName,
String classOutputDir, String libraryHome){
initialize(apiServerURL, apiKey, modelPackageName, apiPackageName, classOutputDir, "model", "api", libraryHome);
}
/**
* Generate classes needed for the model and API invocation
*/
@ -107,6 +116,7 @@ public class LibraryCodeGenerator {
List<Resource> resources = apiMarshaller.readResourceDocumentation();
preprocess(resources);
StringTemplateGroup aTemplateGroup = new StringTemplateGroup(languageConfig.getTemplateLocation());
aTemplateGroup.registerRenderer(String.class, new StringRenderer());
if(resources.size() > 0) {
generateVersionHelper(resources.get(0).getApiVersion(), aTemplateGroup);
}

View File

@ -0,0 +1,31 @@
package com.wordnik.swagger.codegen;
import org.antlr.stringtemplate.AttributeRenderer;
class StringRenderer implements AttributeRenderer {
@Override
public String toString(Object o) {
if (o == null) {
return "";
}
return o.toString();
}
@Override
public String toString(Object o, String formatName) {
if (o == null) {
return "";
}
String result = o.toString();
if (formatName != null && "xml-safe".equals(formatName)) {
result = result.replace("<", "%lt;").replace(">", "&gt;");
}
return result;
}
}

View File

@ -0,0 +1,274 @@
/**
* Copyright 2011 Wordnik, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wordnik.swagger.codegen.config.csharp;
import com.wordnik.swagger.codegen.config.DataTypeMappingProvider;
import com.wordnik.swagger.codegen.config.NamingPolicyProvider;
import com.wordnik.swagger.codegen.config.common.CamelCaseNamingPolicyProvider;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* User: marek-stoj
* Date: 5/11/12
* Time: 5:56 PM
*/
public class CSharpDataTypeMappingProvider implements DataTypeMappingProvider {
private static final Map<String, String> _primitiveValueMap;
private static final Map<String, String> _primitiveObjectMap;
private NamingPolicyProvider _nameGenerator = new CSharpNamingPolicyProvider();
static {
_primitiveValueMap = new HashMap<String, String>();
_primitiveValueMap.put("string", "string");
_primitiveValueMap.put("String", "string");
_primitiveValueMap.put("int", "int");
_primitiveValueMap.put("integer", "int");
_primitiveValueMap.put("Integer", "int");
_primitiveValueMap.put("boolean", "bool");
_primitiveValueMap.put("Boolean", "bool");
_primitiveValueMap.put("long", "long");
_primitiveValueMap.put("Long", "long");
_primitiveValueMap.put("float", "float");
_primitiveValueMap.put("Float", "float");
_primitiveValueMap.put("Date", "DateTime");
_primitiveValueMap.put("date", "DateTime");
_primitiveValueMap.put("Byte", "byte");
_primitiveObjectMap = new HashMap<String, String>();
_primitiveObjectMap.put("string", "string");
_primitiveObjectMap.put("String", "string");
_primitiveObjectMap.put("java.lang.String", "string");
_primitiveObjectMap.put("int", "int");
_primitiveObjectMap.put("integer", "int");
_primitiveObjectMap.put("Integer", "int");
_primitiveObjectMap.put("java.lang.Integer", "int");
_primitiveObjectMap.put("boolean", "bool");
_primitiveObjectMap.put("Boolean", "bool");
_primitiveObjectMap.put("java.lang.Boolean", "bool");
_primitiveObjectMap.put("long", "long");
_primitiveObjectMap.put("Long", "long");
_primitiveObjectMap.put("java.lang.Long", "long");
_primitiveObjectMap.put("float", "float");
_primitiveObjectMap.put("Float", "float");
_primitiveObjectMap.put("java.lang.Float", "float");
_primitiveObjectMap.put("Date", "DateTime");
_primitiveObjectMap.put("date", "DateTime");
_primitiveObjectMap.put("java.util.Date", "DateTime");
_primitiveObjectMap.put("byte", "byte");
}
@Override
public boolean isPrimitiveType(String type) {
if (_primitiveObjectMap.containsKey(type)) {
return true;
}
return false;
}
@Override
public String getListReturnTypeSignature(String typeClass) {
return "List<" + _nameGenerator.applyClassNamingPolicy(typeClass) + ">";
}
@Override
public String getMapReturnTypeSignature(String typeClass) {
return "Dictionary<" + _nameGenerator.applyClassNamingPolicy(typeClass) + ">";
}
@Override
public String getSetReturnTypeSignature(String typeClass) {
return "HashSet<" + _nameGenerator.applyClassNamingPolicy(typeClass) + ">";
}
@Override
public String getArrayReturnTypeSignature(String typeClass) {
return _nameGenerator.applyClassNamingPolicy(typeClass) + "[]";
}
@Override
public String generateListInitialization(String typeClass) {
return " new List<" + _nameGenerator.applyClassNamingPolicy(typeClass) + ">()";
}
@Override
public String generateMapInitialization(String typeClass) {
return " new Dictionary<" + _nameGenerator.applyClassNamingPolicy(typeClass) + ">()";
}
@Override
public String generateSetInitialization(String typeClass) {
return " new HashSet<" + _nameGenerator.applyClassNamingPolicy(typeClass) + ">()";
}
@Override
public String generateArrayInitialization(String typeClass) {
return " null";
}
@Override
public List<String> getListIncludes() {
List<String> imports = new ArrayList<String>();
imports.add("System.Collections.Generic");
return imports;
}
@Override
public List<String> getMapIncludes() {
List<String> imports = new ArrayList<String>();
imports.add("System.Collections.Generic");
return imports;
}
@Override
public List<String> getSetIncludes() {
List<String> imports = new ArrayList<String>();
imports.add("System.Collections.Generic");
return imports;
}
@Override
public List<String> getDateIncludes() {
return new ArrayList<String>();
}
/**
* Gets the short name of the class the class.
* Input can be MAP, LIST or regular string. In case of map or list the class name will be class name
* that map or list is returning.
* @param type
* @return
*/
@Override
public String getGenericType(String type) {
String classShortName = "";
if (type.startsWith("List[")) {
classShortName = type.substring(5, type.length() - 1);
classShortName = getClassType(classShortName, true);
}
else if (type.startsWith("Map[")) {
classShortName = type.substring(4, type.length() - 1);
classShortName = getClassType(classShortName, true);
}
else if (type.startsWith("Set[")) {
classShortName = type.substring(4, type.length() - 1);
classShortName = getClassType(classShortName, true);
}
else if (type.startsWith("Array[")) {
classShortName = type.substring(6, type.length() - 1);
classShortName = getClassType(classShortName, true);
}
else if (type.equalsIgnoreCase("ok")) {
classShortName = "void";
}
else {
classShortName = getClassType(type, true);
}
return classShortName;
}
/**
* Returns the syntax for defintion of an object of type and name
*
* @param argumentType
* @param argumentName
* @return
*/
@Override
public String getArgumentDefinition(String argumentType, String argumentName) {
return argumentType + " " + argumentName;
}
/**
* Gets the class of the expected return value for a type string. Examples of type Strings are int, User, List[User]
* If the type string is a collection type like a map or list the string value returned would be the class
* that map or list is returning.
*
* @param type
* @return
*/
@Override
public String getClassType(String type, boolean primitiveObject) {
if (type.equalsIgnoreCase("void") || type.equalsIgnoreCase("ok")) {
return "void";
}
String classShortName = "";
if (type.startsWith("List[")) {
classShortName = type.substring(5, type.length() - 1);
classShortName = "List<" + getClassType(classShortName, true) + ">";
}
else if (type.startsWith("Map[")) {
classShortName = type.substring(4, type.length() - 1);
String[] mapTypes = classShortName.split(",");
classShortName = "Map<" + getClassType(mapTypes[0], true) + "," + getClassType(mapTypes[1], true) + ">";
}
else if (type.startsWith("Set[")) {
classShortName = type.substring(4, type.length() - 1);
classShortName = "Set<" + getClassType(classShortName, true) + ">";
}
else if (type.startsWith("Array[")) {
classShortName = type.substring(6, type.length() - 1);
classShortName = getClassName(classShortName, true) + "[]";
}
else {
classShortName = getClassName(type, true);
}
return classShortName;
}
/**
* If the data type is primitive and it is expecting object structure then return primitive objects
* else return primitive types
* @param type
* @param primitiveObject -- indicates if the object is primitive or not
* @return
*/
private String getClassName(String type, boolean primitiveObject) {
if (isPrimitiveType(type)) {
if (primitiveObject) {
return _primitiveObjectMap.get(type);
}
else {
return _primitiveValueMap.get(type);
}
}
else {
return _nameGenerator.applyClassNamingPolicy(type);
}
}
@Override
public String generateVariableInitialization(String typeClass) {
return "";
}
}

View File

@ -0,0 +1,122 @@
/**
* Copyright 2011 Wordnik, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wordnik.swagger.codegen.config.csharp;
import com.wordnik.swagger.codegen.LibraryCodeGenerator;
import com.wordnik.swagger.codegen.config.ApiConfiguration;
import com.wordnik.swagger.codegen.config.LanguageConfiguration;
import com.wordnik.swagger.codegen.exception.CodeGenerationException;
import com.wordnik.swagger.codegen.util.FileUtil;
import java.io.File;
/**
* User: marek-stoj
* Date: 5/11/12
* Time: 5:56 PM
*/
public class CSharpLibCodeGen extends LibraryCodeGenerator {
public static void main(String[] args) {
if (args.length < 1) {
throw new CodeGenerationException("Invalid number of arguments passed: No command line argument was passed to the program for config json");
}
if (args.length == 1) {
String configPath = args[0];
CSharpLibCodeGen codeGenerator = new CSharpLibCodeGen(configPath);
codeGenerator.generateCode();
}
if (args.length == 4) {
String apiServerURL = args[0];
if (!apiServerURL.endsWith("/")) {
apiServerURL = apiServerURL + "/";
}
String apiKey = args[1];
String packageName = args[2];
String libraryHome = args[3];
if (libraryHome.endsWith("/")) {
libraryHome = libraryHome.substring(0, libraryHome.length() - 1);
}
String modelPackageName = packageName + ".Model";
String apiPackageName = packageName + ".Api";
String classOutputDir = libraryHome + "/" + packageName.replace(".", "/");
CSharpLibCodeGen codeGenerator =
new CSharpLibCodeGen(
apiServerURL,
apiKey,
modelPackageName,
apiPackageName,
classOutputDir,
libraryHome);
ApiConfiguration config = codeGenerator.getConfig();
config.setDefaultServiceBaseClass("ApiBase");
codeGenerator.generateCode();
}
}
public CSharpLibCodeGen(String apiServerURL, String apiKey, String modelPackageName, String apiPackageName, String classOutputDir, String libraryHome) {
super(apiServerURL, apiKey, modelPackageName, apiPackageName, classOutputDir, "Model", "Api", libraryHome);
this.setDataTypeMappingProvider(new CSharpDataTypeMappingProvider());
this.setNameGenerator(new CSharpNamingPolicyProvider());
}
public CSharpLibCodeGen(String configPath) {
super(configPath);
this.setDataTypeMappingProvider(new CSharpDataTypeMappingProvider());
this.setNameGenerator(new CSharpNamingPolicyProvider());
}
@Override
protected LanguageConfiguration initializeLangConfig(LanguageConfiguration cSharpConfiguration) {
cSharpConfiguration.setClassFileExtension(".cs");
cSharpConfiguration.setTemplateLocation("conf/csharp/templates");
cSharpConfiguration.setStructureLocation("conf/csharp/structure");
cSharpConfiguration.setExceptionPackageName("Swagger.Exceptions");
cSharpConfiguration.setAnnotationPackageName("Swagger.Attributes");
cSharpConfiguration.setMethodOverloadingSupported(true);
FileUtil.createOutputDirectories(cSharpConfiguration.getModelClassLocation(), cSharpConfiguration.getClassFileExtension());
FileUtil.createOutputDirectories(cSharpConfiguration.getResourceClassLocation(), cSharpConfiguration.getClassFileExtension());
FileUtil.clearFolder(cSharpConfiguration.getModelClassLocation());
FileUtil.clearFolder(cSharpConfiguration.getResourceClassLocation());
FileUtil.copyDirectoryFromUrl(
this.getClass().getClassLoader().getResource(cSharpConfiguration.getStructureLocation()),
new File(cSharpConfiguration.getResourceClassLocation()).getParentFile().getParentFile());
return cSharpConfiguration;
}
@Override
protected boolean canEnumNameStartsWithNumber() {
return false;
}
}

View File

@ -0,0 +1,211 @@
/**
* Copyright 2011 Wordnik, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wordnik.swagger.codegen.config.csharp;
import com.wordnik.swagger.codegen.exception.CodeGenerationException;
import com.wordnik.swagger.codegen.config.NamingPolicyProvider;
/**
* User: marek-stoj
* Date: 5/11/12
* Time: 5:56 PM
*/
public class CSharpNamingPolicyProvider implements NamingPolicyProvider {
public static String INPUT_OBJECT_SUFFIX = "Input";
/**
* gets the name of class that is responsible for tracking current library version
* @return
*/
@Override
public String getVersionCheckerClassName() {
return "VersionChecker";
}
/**
* Converts the first character of the input into upper case .
* Example: If the input is word, the return value will be Word
* @param input
* @return
*/
@Override
public String applyClassNamingPolicy(String input) {
if (input != null && input.length() > 0) {
if ("string".equalsIgnoreCase(input)) {
return "string";
}
String output = input.substring(0, 1).toUpperCase() + input.substring(1);
// class name can't have . so if dot exists remove the same
output = output.replace(".", "");
return output;
}
else {
throw new CodeGenerationException("Error converting input to first letter caps becuase of null or empty input");
}
}
/**
* Converts the first character of the input into upper case.
* Example: If the input is getWord, the return value will be GetWord
* @param input
* @return
*/
@Override
public String applyMethodNamingPolicy(String input) {
if (input != null && input.length() > 0) {
return input.substring(0, 1).toUpperCase() + input.substring(1);
}
else {
throw new CodeGenerationException("Error converting input to first letter to upper because of null or empty input");
}
}
/**
* Generate name of the service from resource path.
*
* Example: if input is /user.json the generated name for this path will be UserAPI
* If the input is /user.json/{userId}, the service name will still be generated as UserAPI
*
* @param resourcePath
* @return
*/
@Override
public String getServiceName(String resourcePath) {
String className = null;
int index = resourcePath.indexOf(".");
if (index >= 0) {
String resourceName = resourcePath.substring(1, index);
className = applyClassNamingPolicy(resourceName);
}
else {
String[] paths = resourcePath.split("/");
for (String path : paths) {
if (path != null && path.length() > 0) {
className = applyClassNamingPolicy(path);
break;
}
}
}
return className + "Api";
}
/**
* Generates the name of service methods.
*
* Resource documentation provides suggested names. Individual language can choose to use suggested name or
* generate the name based on end point path. Example: IN java we use suggested name
*
* @param endPoint
* @param suggestedName
* @return
*/
@Override
public String getMethodName(String endPoint, String suggestedName) {
return suggestedName;
}
/**
* For input UserAPI and resource path /findUserById the suggested input object name will be: UserFindUserByIdInput
*
* If the input path is /{userId}/delete the suggested name will be UserDeleteInput. The path parameters are ignored
* in generating the input object name
*
* Note: Input objects are only created when the number of input arguments in a method exceeds certain number so <br/> that the method signatures are clean
*
*
* @param serviceName
* @param resourcePath
* @return
*/
@Override
public String getInputObjectName(String serviceName, String resourcePath) {
// Since service name has Api at the end remove that format he name
String inputobjectName = serviceName.substring(0, serviceName.length() - 3);
String[] pathElements = resourcePath.split("/");
StringBuilder urlPath = new StringBuilder("");
if (pathElements != null) {
for (int i = 0; i < pathElements.length; i++) {
String pathElement = pathElements[i];
if (pathElement != null && pathElement.length() > 0) {
int position = pathElement.indexOf("{");
if (position < 0) {
inputobjectName = inputobjectName + applyClassNamingPolicy(pathElement) + INPUT_OBJECT_SUFFIX;
}
}
}
}
return inputobjectName;
}
/**
* Generate the name of the wrapper class used as a wrapper for a list of items returned by a service
* <p/>
* Example: get definitions API returns a list of definition objects as the result. This will be wrapped by an
* object. The object's name will be determined by invoking this service.
* eg. DefinitionList for a wrapper of 'definition's
*
* @param wrapperItemName
* @return
*/
@Override
public String getListWrapperName(String wrapperItemName) {
return applyClassNamingPolicy(wrapperItemName) + "List";
}
/**
* Generates a name for an enum for the param or field name.
* <p/>
* Example: for a param source the return could be SourceEnum
*
* @param input
* @return
*/
@Override
public String getEnumName(String input) {
if (input != null && input.length() > 0) {
return this.applyClassNamingPolicy(input).concat("Values");
}
else {
throw new CodeGenerationException("Error getting Enum name becuase of null input");
}
}
/**
* Gets the signature of the method that gets value for give attribute name.
*
* Example: If class name is user and attibute name is email the out in java language will be
* <code>user.getEmail()</code>
*
* @param className
* @param attributeName
* @return
*/
@Override
public String createGetterMethodName(String className, String attributeName) {
return className + "." + applyClassNamingPolicy(attributeName);
}
}

View File

@ -234,7 +234,7 @@ public class EndpointOperation {
modelField.getName().equals(AUTH_TOKEN_PARAM_NAME)){
method.setAuthToken(true);
anArgument.setName(AUTH_TOKEN_ARGUMENT_NAME);
anArgument.setDataType(MethodArgument.ARGUMENT_STRING);
anArgument.setDataType(dataTypeMapper.getClassType(MethodArgument.ARGUMENT_STRING, true));
anArgument.setDescription(modelField.getDescription());
anArgument.setRequired(modelField.isRequired());
anArgument.setDefaultValue(modelField.getDefaultValue());
@ -243,14 +243,14 @@ public class EndpointOperation {
}else if(modelField.getParamType().equalsIgnoreCase(PARAM_TYPE_HEADER) &&
modelField.getName().equals(API_KEY_PARAM_NAME)){
anArgument.setName(API_KEY_PARAM_NAME);
anArgument.setDataType(MethodArgument.ARGUMENT_STRING);
anArgument.setDataType(dataTypeMapper.getClassType(MethodArgument.ARGUMENT_STRING, true));
anArgument.setRequired(true);
arguments.add(anArgument);
headerParams.add(anArgument);
}else if (modelField.getParamType().equalsIgnoreCase(PARAM_TYPE_PATH) &&
!modelField.getName().equalsIgnoreCase(FORMAT_PARAM_NAME)) {
anArgument.setName(modelField.getName());
anArgument.setDataType(MethodArgument.ARGUMENT_STRING);
anArgument.setDataType(dataTypeMapper.getClassType(MethodArgument.ARGUMENT_STRING, true));
anArgument.setDescription(modelField.getDescription());
anArgument.setRequired(true); // always true
anArgument.setDefaultValue(modelField.getDefaultValue());
@ -258,7 +258,7 @@ public class EndpointOperation {
pathParams.add(anArgument);
}else if (modelField.getParamType().equalsIgnoreCase(PARAM_TYPE_QUERY)) {
anArgument.setName(modelField.getName());
anArgument.setDataType(MethodArgument.ARGUMENT_STRING);
anArgument.setDataType(dataTypeMapper.getClassType(MethodArgument.ARGUMENT_STRING, true));
anArgument.setDescription(modelField.getDescription());
anArgument.setRequired(modelField.isRequired());
anArgument.setDefaultValue(modelField.getDefaultValue());