Skip to content

Commit 41c0034

Browse files
committed
Merge pull request #2243 from wing328/python_better_reserved_word
[Pytthon] better reserved word handling for objc
2 parents 005584c + 2d4ccbf commit 41c0034

File tree

16 files changed

+352
-173
lines changed

16 files changed

+352
-173
lines changed

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

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -249,12 +249,12 @@ public String getSwaggerType(Property p) {
249249
if (typeMapping.containsKey(swaggerType)) {
250250
type = typeMapping.get(swaggerType);
251251
if (languageSpecificPrimitives.contains(type) && !foundationClasses.contains(type)) {
252-
return toModelName(type);
252+
return toModelNameWithoutReservedWordCheck(type);
253253
}
254254
} else {
255255
type = swaggerType;
256256
}
257-
return toModelName(type);
257+
return toModelNameWithoutReservedWordCheck(type);
258258
}
259259

260260
@Override
@@ -314,6 +314,23 @@ else if (languageSpecificPrimitives.contains(swaggerType)) {
314314

315315
@Override
316316
public String toModelName(String type) {
317+
// model name cannot use reserved keyword
318+
if (reservedWords.contains(type)) {
319+
LOGGER.warn(type+ " (reserved word) cannot be used as model name. Renamed to " + ("object_" + type) + " before further processing");
320+
type = "object_" + type; // e.g. return => ObjectReturn (after camelize)
321+
}
322+
323+
return toModelNameWithoutReservedWordCheck(type);
324+
}
325+
326+
/*
327+
* Convert input to proper model name according to ObjC style guide
328+
* without checking for reserved words
329+
*
330+
* @param type Model anme
331+
* @return model Name in ObjC style guide
332+
*/
333+
public String toModelNameWithoutReservedWordCheck(String type) {
317334
type = type.replaceAll("[^0-9a-zA-Z_]", "_"); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'.
318335

319336
// language build-in classes
@@ -425,7 +442,8 @@ public String toOperationId(String operationId) {
425442

426443
// method name cannot use reserved keyword, e.g. return
427444
if (reservedWords.contains(operationId)) {
428-
throw new RuntimeException(operationId + " (reserved word) cannot be used as method name");
445+
LOGGER.warn(operationId + " (reserved word) cannot be used as method name. Renamed to " + camelize(sanitizeName("call_" + operationId), true));
446+
operationId = "call_" + operationId;
429447
}
430448

431449
return camelize(sanitizeName(operationId), true);

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

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,8 @@ public String toModelName(String name) {
219219

220220
// model name cannot use reserved keyword, e.g. return
221221
if (reservedWords.contains(name)) {
222-
throw new RuntimeException(name + " (reserved word) cannot be used as a model name");
222+
LOGGER.warn(name + " (reserved word) cannot be used as model name. Renamed to " + camelize("object_" + name));
223+
name = "object_" + name; // e.g. return => ObjectReturn (after camelize)
223224
}
224225

225226
// camelize the model name
@@ -231,7 +232,8 @@ public String toModelName(String name) {
231232
public String toModelFilename(String name) {
232233
// model name cannot use reserved keyword, e.g. return
233234
if (reservedWords.contains(name)) {
234-
throw new RuntimeException(name + " (reserved word) cannot be used as a model name");
235+
LOGGER.warn(name + " (reserved word) cannot be used as model filename. Renamed to " + underscore(dropDots("object_" + name)));
236+
name = "object_" + name; // e.g. return => ObjectReturn (after camelize)
235237
}
236238

237239
// underscore the model file name
@@ -267,14 +269,15 @@ public String toApiVarName(String name) {
267269

268270
@Override
269271
public String toOperationId(String operationId) {
270-
// throw exception if method name is empty
272+
// throw exception if method name is empty (should not occur as an auto-generated method name will be used)
271273
if (StringUtils.isEmpty(operationId)) {
272274
throw new RuntimeException("Empty method name (operationId) not allowed");
273275
}
274276

275277
// method name cannot use reserved keyword, e.g. return
276278
if (reservedWords.contains(operationId)) {
277-
throw new RuntimeException(operationId + " (reserved word) cannot be used as method name");
279+
LOGGER.warn(operationId + " (reserved word) cannot be used as method name. Renamed to " + underscore(sanitizeName("call_" + operationId)));
280+
operationId = "call_" + operationId;
278281
}
279282

280283
return underscore(sanitizeName(operationId));

modules/swagger-codegen/src/test/java/io/swagger/codegen/python/PythonTest.java

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,28 @@
22

33
import io.swagger.codegen.CodegenModel;
44
import io.swagger.codegen.CodegenOperation;
5+
import io.swagger.codegen.CodegenProperty;
56
import io.swagger.codegen.DefaultCodegen;
67
import io.swagger.codegen.languages.PythonClientCodegen;
8+
import io.swagger.models.ArrayModel;
9+
import io.swagger.models.Model;
10+
import io.swagger.models.ModelImpl;
711
import io.swagger.models.Operation;
812
import io.swagger.models.Swagger;
13+
import io.swagger.models.properties.ArrayProperty;
14+
import io.swagger.models.properties.DateTimeProperty;
15+
import io.swagger.models.properties.LongProperty;
16+
import io.swagger.models.properties.MapProperty;
17+
import io.swagger.models.properties.RefProperty;
18+
import io.swagger.models.properties.StringProperty;
919
import io.swagger.parser.SwaggerParser;
1020

1121
import org.testng.Assert;
1222
import org.testng.annotations.Test;
23+
import org.testng.annotations.ITestAnnotation;
24+
25+
import com.google.common.collect.Sets;
26+
import java.util.Map;
1327

1428
@SuppressWarnings("static-method")
1529
public class PythonTest {
@@ -35,4 +49,232 @@ public void modelTest() {
3549
Assert.assertEquals(codegenOperation.returnType, "V1beta3Binding");
3650
Assert.assertEquals(codegenOperation.returnBaseType, "V1beta3Binding");
3751
}
52+
53+
@Test(description = "convert a simple java model")
54+
public void simpleModelTest() {
55+
final Model model = new ModelImpl()
56+
.description("a sample model")
57+
.property("id", new LongProperty())
58+
.property("name", new StringProperty())
59+
.property("createdAt", new DateTimeProperty())
60+
.required("id")
61+
.required("name");
62+
final DefaultCodegen codegen = new PythonClientCodegen();
63+
final CodegenModel cm = codegen.fromModel("sample", model);
64+
65+
Assert.assertEquals(cm.name, "sample");
66+
Assert.assertEquals(cm.classname, "Sample");
67+
Assert.assertEquals(cm.description, "a sample model");
68+
Assert.assertEquals(cm.vars.size(), 3);
69+
70+
final CodegenProperty property1 = cm.vars.get(0);
71+
Assert.assertEquals(property1.baseName, "id");
72+
Assert.assertEquals(property1.datatype, "int");
73+
Assert.assertEquals(property1.name, "id");
74+
Assert.assertNull(property1.defaultValue);
75+
Assert.assertEquals(property1.baseType, "int");
76+
Assert.assertTrue(property1.hasMore);
77+
Assert.assertTrue(property1.required);
78+
Assert.assertTrue(property1.isPrimitiveType);
79+
Assert.assertTrue(property1.isNotContainer);
80+
81+
final CodegenProperty property2 = cm.vars.get(1);
82+
Assert.assertEquals(property2.baseName, "name");
83+
Assert.assertEquals(property2.datatype, "str");
84+
Assert.assertEquals(property2.name, "name");
85+
Assert.assertNull(property2.defaultValue);
86+
Assert.assertEquals(property2.baseType, "str");
87+
Assert.assertTrue(property2.hasMore);
88+
Assert.assertTrue(property2.required);
89+
Assert.assertTrue(property2.isPrimitiveType);
90+
Assert.assertTrue(property2.isNotContainer);
91+
92+
final CodegenProperty property3 = cm.vars.get(2);
93+
Assert.assertEquals(property3.baseName, "createdAt");
94+
Assert.assertEquals(property3.datatype, "datetime");
95+
Assert.assertEquals(property3.name, "created_at");
96+
Assert.assertNull(property3.defaultValue);
97+
Assert.assertEquals(property3.baseType, "datetime");
98+
Assert.assertNull(property3.hasMore);
99+
Assert.assertNull(property3.required);
100+
Assert.assertTrue(property3.isNotContainer);
101+
}
102+
103+
@Test(description = "convert a model with list property")
104+
public void listPropertyTest() {
105+
final Model model = new ModelImpl()
106+
.description("a sample model")
107+
.property("id", new LongProperty())
108+
.property("urls", new ArrayProperty()
109+
.items(new StringProperty()))
110+
.required("id");
111+
final DefaultCodegen codegen = new PythonClientCodegen();
112+
final CodegenModel cm = codegen.fromModel("sample", model);
113+
114+
Assert.assertEquals(cm.name, "sample");
115+
Assert.assertEquals(cm.classname, "Sample");
116+
Assert.assertEquals(cm.description, "a sample model");
117+
Assert.assertEquals(cm.vars.size(), 2);
118+
119+
final CodegenProperty property1 = cm.vars.get(0);
120+
Assert.assertEquals(property1.baseName, "id");
121+
Assert.assertEquals(property1.datatype, "int");
122+
Assert.assertEquals(property1.name, "id");
123+
Assert.assertNull(property1.defaultValue);
124+
Assert.assertEquals(property1.baseType, "int");
125+
Assert.assertTrue(property1.hasMore);
126+
Assert.assertTrue(property1.required);
127+
Assert.assertTrue(property1.isPrimitiveType);
128+
Assert.assertTrue(property1.isNotContainer);
129+
130+
final CodegenProperty property2 = cm.vars.get(1);
131+
Assert.assertEquals(property2.baseName, "urls");
132+
Assert.assertEquals(property2.datatype, "list[str]");
133+
Assert.assertEquals(property2.name, "urls");
134+
Assert.assertNull(property2.defaultValue);
135+
Assert.assertEquals(property2.baseType, "list");
136+
Assert.assertNull(property2.hasMore);
137+
Assert.assertEquals(property2.containerType, "array");
138+
Assert.assertNull(property2.required);
139+
Assert.assertTrue(property2.isPrimitiveType);
140+
Assert.assertTrue(property2.isContainer);
141+
}
142+
143+
@Test(description = "convert a model with a map property")
144+
public void mapPropertyTest() {
145+
final Model model = new ModelImpl()
146+
.description("a sample model")
147+
.property("translations", new MapProperty()
148+
.additionalProperties(new StringProperty()))
149+
.required("id");
150+
final DefaultCodegen codegen = new PythonClientCodegen();
151+
final CodegenModel cm = codegen.fromModel("sample", model);
152+
153+
Assert.assertEquals(cm.name, "sample");
154+
Assert.assertEquals(cm.classname, "Sample");
155+
Assert.assertEquals(cm.description, "a sample model");
156+
Assert.assertEquals(cm.vars.size(), 1);
157+
158+
final CodegenProperty property1 = cm.vars.get(0);
159+
Assert.assertEquals(property1.baseName, "translations");
160+
Assert.assertEquals(property1.datatype, "dict(str, str)");
161+
Assert.assertEquals(property1.name, "translations");
162+
Assert.assertEquals(property1.baseType, "dict");
163+
Assert.assertEquals(property1.containerType, "map");
164+
Assert.assertNull(property1.required);
165+
Assert.assertTrue(property1.isContainer);
166+
Assert.assertTrue(property1.isPrimitiveType);
167+
}
168+
169+
@Test(description = "convert a model with complex property")
170+
public void complexPropertyTest() {
171+
final Model model = new ModelImpl()
172+
.description("a sample model")
173+
.property("children", new RefProperty("#/definitions/Children"));
174+
final DefaultCodegen codegen = new PythonClientCodegen();
175+
final CodegenModel cm = codegen.fromModel("sample", model);
176+
177+
Assert.assertEquals(cm.name, "sample");
178+
Assert.assertEquals(cm.classname, "Sample");
179+
Assert.assertEquals(cm.description, "a sample model");
180+
Assert.assertEquals(cm.vars.size(), 1);
181+
182+
final CodegenProperty property1 = cm.vars.get(0);
183+
Assert.assertEquals(property1.baseName, "children");
184+
Assert.assertEquals(property1.datatype, "Children");
185+
Assert.assertEquals(property1.name, "children");
186+
Assert.assertEquals(property1.baseType, "Children");
187+
Assert.assertNull(property1.required);
188+
Assert.assertTrue(property1.isNotContainer);
189+
}
190+
191+
@Test(description = "convert a model with complex list property")
192+
public void complexListPropertyTest() {
193+
final Model model = new ModelImpl()
194+
.description("a sample model")
195+
.property("children", new ArrayProperty()
196+
.items(new RefProperty("#/definitions/Children")));
197+
final DefaultCodegen codegen = new PythonClientCodegen();
198+
final CodegenModel cm = codegen.fromModel("sample", model);
199+
200+
Assert.assertEquals(cm.name, "sample");
201+
Assert.assertEquals(cm.classname, "Sample");
202+
Assert.assertEquals(cm.description, "a sample model");
203+
Assert.assertEquals(cm.vars.size(), 1);
204+
205+
final CodegenProperty property1 = cm.vars.get(0);
206+
Assert.assertEquals(property1.baseName, "children");
207+
Assert.assertEquals(property1.complexType, "Children");
208+
Assert.assertEquals(property1.datatype, "list[Children]");
209+
Assert.assertEquals(property1.name, "children");
210+
Assert.assertEquals(property1.baseType, "list");
211+
Assert.assertEquals(property1.containerType, "array");
212+
Assert.assertNull(property1.required);
213+
Assert.assertTrue(property1.isContainer);
214+
}
215+
216+
@Test(description = "convert a model with complex map property")
217+
public void complexMapPropertyTest() {
218+
final Model model = new ModelImpl()
219+
.description("a sample model")
220+
.property("children", new MapProperty()
221+
.additionalProperties(new RefProperty("#/definitions/Children")));
222+
final DefaultCodegen codegen = new PythonClientCodegen();
223+
final CodegenModel cm = codegen.fromModel("sample", model);
224+
225+
Assert.assertEquals(cm.name, "sample");
226+
Assert.assertEquals(cm.classname, "Sample");
227+
Assert.assertEquals(cm.description, "a sample model");
228+
Assert.assertEquals(cm.vars.size(), 1);
229+
Assert.assertEquals(Sets.intersection(cm.imports, Sets.newHashSet("Children")).size(), 1);
230+
231+
final CodegenProperty property1 = cm.vars.get(0);
232+
Assert.assertEquals(property1.baseName, "children");
233+
Assert.assertEquals(property1.complexType, "Children");
234+
Assert.assertEquals(property1.datatype, "dict(str, Children)");
235+
Assert.assertEquals(property1.name, "children");
236+
Assert.assertEquals(property1.baseType, "dict");
237+
Assert.assertEquals(property1.containerType, "map");
238+
Assert.assertNull(property1.required);
239+
Assert.assertTrue(property1.isContainer);
240+
Assert.assertNull(property1.isNotContainer);
241+
}
242+
243+
244+
// should not start with 'null'. need help from the community to investigate further
245+
@Test(enabled = false, description = "convert an array model")
246+
public void arrayModelTest() {
247+
final Model model = new ArrayModel()
248+
.description("an array model")
249+
.items(new RefProperty("#/definitions/Children"));
250+
final DefaultCodegen codegen = new PythonClientCodegen();
251+
final CodegenModel cm = codegen.fromModel("sample", model);
252+
253+
Assert.assertEquals(cm.name, "sample");
254+
Assert.assertEquals(cm.classname, "Sample");
255+
Assert.assertEquals(cm.description, "an array model");
256+
Assert.assertEquals(cm.vars.size(), 0);
257+
Assert.assertEquals(cm.parent, "null<Children>");
258+
Assert.assertEquals(cm.imports.size(), 1);
259+
Assert.assertEquals(Sets.intersection(cm.imports, Sets.newHashSet("Children")).size(), 1);
260+
}
261+
262+
// should not start with 'null'. need help from the community to investigate further
263+
@Test(enabled = false, description = "convert an map model")
264+
public void mapModelTest() {
265+
final Model model = new ModelImpl()
266+
.description("a map model")
267+
.additionalProperties(new RefProperty("#/definitions/Children"));
268+
final DefaultCodegen codegen = new PythonClientCodegen();
269+
final CodegenModel cm = codegen.fromModel("sample", model);
270+
271+
Assert.assertEquals(cm.name, "sample");
272+
Assert.assertEquals(cm.classname, "Sample");
273+
Assert.assertEquals(cm.description, "a map model");
274+
Assert.assertEquals(cm.vars.size(), 0);
275+
Assert.assertEquals(cm.parent, "null<String, Children>");
276+
Assert.assertEquals(cm.imports.size(), 2); // TODO: need to verify
277+
Assert.assertEquals(Sets.intersection(cm.imports, Sets.newHashSet("Children")).size(), 1);
278+
}
279+
38280
}

samples/client/petstore/objc/SwaggerClient/SWGApiClient.m

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,8 @@ + (NSString *) selectHeaderAccept:(NSArray *)accepts {
136136
NSMutableArray *lowerAccepts = [[NSMutableArray alloc] initWithCapacity:[accepts count]];
137137
for (NSString *string in accepts) {
138138
NSString * lowerAccept = [string lowercaseString];
139-
if ([lowerAccept containsString:@"application/json"]) {
139+
// use rangeOfString instead of containsString for iOS 7 support
140+
if ([lowerAccept rangeOfString:@"application/json"].location != NSNotFound) {
140141
return @"application/json";
141142
}
142143
[lowerAccepts addObject:lowerAccept];

0 commit comments

Comments
 (0)