Skip to content

Commit 9dc4012

Browse files
committed
[csharp] Options: useCollection, returnICollection
This change is inline with Microsoft's recommended guidelines for collects (https://msdn.microsoft.com/en-us/library/dn169389(v=vs.110).aspx). Added generator options for csharp to: * useCollection: Deserialize responses into and return Collection<T> * returnICollection: For List<T> or Collection<T>, return ICollection<T> instead of the concrete type As a consequence of useCollection, method imputs will also change to Collection<T>.
1 parent 421b70c commit 9dc4012

File tree

14 files changed

+94
-3
lines changed

14 files changed

+94
-3
lines changed

modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenConstants.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,9 @@ public class CodegenConstants {
6262
public static final String OPTIONAL_ASSEMBLY_INFO = "optionalAssemblyInfo";
6363
public static final String OPTIONAL_ASSEMBLY_INFO_DESC = "Generate AssemblyInfo.cs (Default: true).";
6464

65+
public static final String USE_COLLECTION = "useCollection";
66+
public static final String USE_COLLECTION_DESC = "Deserialize array types to Collection<T> instead of List<T>.";
67+
68+
public static final String RETURN_ICOLLECTION = "returnICollection";
69+
public static final String RETURN_ICOLLECTION_DESC = "Return ICollection<T> instead of the concrete type.";
6570
}

modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/CSharpClientCodegen.java

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import io.swagger.codegen.SupportingFile;
88
import io.swagger.codegen.CodegenProperty;
99
import io.swagger.codegen.CodegenModel;
10+
import io.swagger.codegen.CodegenOperation;
1011
import io.swagger.models.properties.*;
1112
import io.swagger.codegen.CliOption;
1213

@@ -27,6 +28,8 @@ public class CSharpClientCodegen extends DefaultCodegen implements CodegenConfig
2728
protected boolean optionalAssemblyInfoFlag = true;
2829
protected boolean optionalMethodArgumentFlag = true;
2930
protected boolean useDateTimeOffsetFlag = false;
31+
protected boolean useCollection = false;
32+
protected boolean returnICollection = false;
3033
protected String packageTitle = "Swagger Library";
3134
protected String packageProductName = "SwaggerLibrary";
3235
protected String packageDescription = "A library generated from a Swagger doc";
@@ -75,6 +78,8 @@ public CSharpClientCodegen() {
7578
"long?",
7679
"float?",
7780
"byte[]",
81+
"ICollection",
82+
"Collection",
7883
"List",
7984
"Dictionary",
8085
"DateTime?",
@@ -88,7 +93,9 @@ public CSharpClientCodegen() {
8893
"Stream", // not really a primitive, we include it to avoid model import
8994
"Object")
9095
);
96+
9197
instantiationTypes.put("array", "List");
98+
instantiationTypes.put("list", "List");
9299
instantiationTypes.put("map", "Dictionary");
93100

94101
typeMapping = new HashMap<String, String>();
@@ -120,6 +127,11 @@ public CSharpClientCodegen() {
120127
CodegenConstants.OPTIONAL_ASSEMBLY_INFO_DESC).defaultValue(Boolean.TRUE.toString()));
121128
cliOptions.add(new CliOption(CodegenConstants.SOURCE_FOLDER, CodegenConstants.SOURCE_FOLDER_DESC).defaultValue(sourceFolder));
122129
cliOptions.add(CliOption.newBoolean(CodegenConstants.USE_DATETIME_OFFSET, CodegenConstants.USE_DATETIME_OFFSET_DESC));
130+
131+
cliOptions.add( CliOption.newBoolean(CodegenConstants.USE_COLLECTION, CodegenConstants.USE_COLLECTION_DESC)
132+
.defaultValue(Boolean.FALSE.toString()) );
133+
cliOptions.add( CliOption.newBoolean(CodegenConstants.RETURN_ICOLLECTION, CodegenConstants.RETURN_ICOLLECTION_DESC)
134+
.defaultValue(Boolean.FALSE.toString()) );
123135
}
124136

125137
@Override
@@ -176,6 +188,14 @@ public void processOpts() {
176188
.get(CodegenConstants.OPTIONAL_ASSEMBLY_INFO).toString()));
177189
}
178190

191+
if (additionalProperties.containsKey(CodegenConstants.USE_COLLECTION)){
192+
setUseCollection(Boolean.valueOf(additionalProperties.get(CodegenConstants.USE_COLLECTION).toString()));
193+
}
194+
195+
if (additionalProperties.containsKey(CodegenConstants.RETURN_ICOLLECTION)){
196+
setReturnICollection(Boolean.valueOf(additionalProperties.get(CodegenConstants.RETURN_ICOLLECTION).toString()));
197+
}
198+
179199
supportingFiles.add(new SupportingFile("Configuration.mustache",
180200
sourceFolder + File.separator + clientPackage.replace(".", java.io.File.separator), "Configuration.cs"));
181201
supportingFiles.add(new SupportingFile("ApiClient.mustache",
@@ -289,6 +309,32 @@ public String toModelFilename(String name) {
289309
return toModelName(name);
290310
}
291311

312+
@Override
313+
public Map<String, Object> postProcessOperations(Map<String, Object> objs) {
314+
super.postProcessOperations(objs);
315+
if(objs != null) {
316+
Map<String, Object> operations = (Map<String, Object>) objs.get("operations");
317+
if (operations != null) {
318+
List<CodegenOperation> ops = (List<CodegenOperation>) operations.get("operation");
319+
for (CodegenOperation operation : ops) {
320+
if (operation.returnType != null) {
321+
operation.returnContainer = operation.returnType;
322+
if( this.returnICollection && (
323+
operation.returnType.startsWith("List")||
324+
operation.returnType.startsWith("Collection")) ) {
325+
// NOTE: ICollection works for both List<T> and Collection<T>
326+
int genericStart = operation.returnType.indexOf("<");
327+
if(genericStart > 0) {
328+
operation.returnType = "ICollection" + operation.returnType.substring(genericStart);
329+
}
330+
}
331+
}
332+
}
333+
}
334+
}
335+
336+
return objs;
337+
}
292338

293339
@Override
294340
public String getTypeDeclaration(Property p) {
@@ -343,6 +389,21 @@ public void setOptionalMethodArgumentFlag(boolean flag) {
343389
this.optionalMethodArgumentFlag = flag;
344390
}
345391

392+
public void setReturnICollection(boolean returnICollection) {
393+
this.returnICollection = returnICollection;
394+
}
395+
396+
public void setUseCollection(boolean useCollection) {
397+
this.useCollection = useCollection;
398+
if(useCollection){
399+
typeMapping.put("array", "Collection");
400+
typeMapping.put("list", "Collection");
401+
402+
instantiationTypes.put("array", "Collection");
403+
instantiationTypes.put("list", "Collection");
404+
}
405+
}
406+
346407
public void useDateTimeOffset(boolean flag) {
347408
this.useDateTimeOffsetFlag = flag;
348409
if (flag)

modules/swagger-codegen/src/main/resources/csharp/api.mustache

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.IO;
33
using System.Collections.Generic;
4+
using System.Collections.ObjectModel;
45
using System.Linq;
56
using RestSharp;
67
using {{packageName}}.Client;
@@ -239,7 +240,7 @@ namespace {{packageName}}.Api
239240

240241
{{#returnType}}return new ApiResponse<{{{returnType}}}>(statusCode,
241242
response.Headers.ToDictionary(x => x.Name, x => x.Value.ToString()),
242-
({{{returnType}}}) Configuration.ApiClient.Deserialize(response, typeof({{{returnType}}})));{{/returnType}}
243+
({{{returnType}}}) Configuration.ApiClient.Deserialize(response, typeof({{#returnContainer}}{{{returnContainer}}}{{/returnContainer}}{{^returnContainer}}{{{returnType}}}{{/returnContainer}})));{{/returnType}}
243244
{{^returnType}}return new ApiResponse<Object>(statusCode,
244245
response.Headers.ToDictionary(x => x.Name, x => x.Value.ToString()),
245246
null);{{/returnType}}
@@ -344,7 +345,7 @@ namespace {{packageName}}.Api
344345

345346
{{#returnType}}return new ApiResponse<{{{returnType}}}>(statusCode,
346347
response.Headers.ToDictionary(x => x.Name, x => x.Value.ToString()),
347-
({{{returnType}}}) Configuration.ApiClient.Deserialize(response, typeof({{{returnType}}})));{{/returnType}}
348+
({{{returnType}}}) Configuration.ApiClient.Deserialize(response, typeof({{#returnContainer}}{{{returnContainer}}}{{/returnContainer}}{{^returnContainer}}{{{returnType}}}{{/returnContainer}})));{{/returnType}}
348349
{{^returnType}}return new ApiResponse<Object>(statusCode,
349350
response.Headers.ToDictionary(x => x.Name, x => x.Value.ToString()),
350351
null);{{/returnType}}

modules/swagger-codegen/src/main/resources/csharp/compile-mono.sh.mustache

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#!/usr/bin/env bash
12
wget -nc https://nuget.org/nuget.exe;
23
mozroots --import --sync
34
mono nuget.exe install vendor/packages.config -o vendor;

modules/swagger-codegen/src/test/java/io/swagger/codegen/options/CSharpClientOptionsProvider.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ public Map<String, String> createOptions() {
2626
.put(CodegenConstants.OPTIONAL_ASSEMBLY_INFO, "true")
2727
.put(CodegenConstants.USE_DATETIME_OFFSET, "true")
2828
.put(CodegenConstants.SOURCE_FOLDER, SOURCE_FOLDER_VALUE)
29+
.put(CodegenConstants.USE_COLLECTION, "false")
30+
.put(CodegenConstants.RETURN_ICOLLECTION, "false")
2931
.build();
3032
}
3133

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#!/usr/bin/env bash
2+
wget -nc https://nuget.org/nuget.exe;
3+
mozroots --import --sync
4+
mono nuget.exe install vendor/packages.config -o vendor;
5+
mkdir -p bin;
6+
mcs -sdk:45 -r:vendor/Newtonsoft.Json.8.0.2/lib/net45/Newtonsoft.Json.dll,\
7+
vendor/RestSharp.105.2.3/lib/net45/RestSharp.dll,\
8+
System.Runtime.Serialization.dll \
9+
-target:library \
10+
-out:bin/IO.Swagger.dll \
11+
-recurse:'src/*.cs' \
12+
-doc:bin/IO.Swagger.xml \
13+
-platform:anycpu

samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Api/PetApi.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.IO;
33
using System.Collections.Generic;
4+
using System.Collections.ObjectModel;
45
using System.Linq;
56
using RestSharp;
67
using IO.Swagger.Client;

samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Api/StoreApi.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.IO;
33
using System.Collections.Generic;
4+
using System.Collections.ObjectModel;
45
using System.Linq;
56
using RestSharp;
67
using IO.Swagger.Client;

samples/client/petstore/csharp/SwaggerClientTest/Lib/SwaggerClient/src/main/csharp/IO/Swagger/Api/UserApi.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.IO;
33
using System.Collections.Generic;
4+
using System.Collections.ObjectModel;
45
using System.Linq;
56
using RestSharp;
67
using IO.Swagger.Client;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<packages>
3+
<package id="RestSharp" version="105.2.3" targetFramework="net45" developmentDependency="true" />
4+
<package id="Newtonsoft.Json" version="8.0.2" targetFramework="net45" developmentDependency="true" />
5+
</packages>

samples/client/petstore/csharp/SwaggerClientTest/TestPet.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ public void TestUploadFile ()
221221
{
222222
Assembly _assembly = Assembly.GetExecutingAssembly();
223223
Stream _imageStream = _assembly.GetManifestResourceStream("SwaggerClientTest.swagger-logo.png");
224-
PetApi petApi = new PetApi ();
224+
PetApi petApi = new PetApi ();
225225
// test file upload with form parameters
226226
petApi.UploadFile(petId, "new form name", _imageStream);
227227

Binary file not shown.
Binary file not shown.
Binary file not shown.

0 commit comments

Comments
 (0)