Skip to content

Commit e983208

Browse files
author
Ole Lensmar
committed
Merge pull request #706 from 0legg/feature/retrofit-templates
[WIP] add template for Retrofit and Gson
2 parents 7d7ed15 + ec08d31 commit e983208

File tree

29 files changed

+1708
-1
lines changed

29 files changed

+1708
-1
lines changed

bin/all-petstore.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ cd $APP_DIR
2727
./bin/qt5-petstore.sh
2828
./bin/php-petstore.sh
2929
./bin/python-petstore.sh
30+
./bin/retrofit-petstore.sh
3031
./bin/ruby-petstore.sh
3132
./bin/objc-petstore.sh
3233
./bin/scala-petstore.sh

bin/retrofit-petstore.sh

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#!/bin/sh
2+
3+
SCRIPT="$0"
4+
5+
while [ -h "$SCRIPT" ] ; do
6+
ls=`ls -ld "$SCRIPT"`
7+
link=`expr "$ls" : '.*-> \(.*\)$'`
8+
if expr "$link" : '/.*' > /dev/null; then
9+
SCRIPT="$link"
10+
else
11+
SCRIPT=`dirname "$SCRIPT"`/"$link"
12+
fi
13+
done
14+
15+
if [ ! -d "${APP_DIR}" ]; then
16+
APP_DIR=`dirname "$SCRIPT"`/..
17+
APP_DIR=`cd "${APP_DIR}"; pwd`
18+
fi
19+
20+
executable="./modules/swagger-codegen-cli/target/swagger-codegen-cli.jar"
21+
22+
if [ ! -f "$executable" ]
23+
then
24+
mvn clean package
25+
fi
26+
27+
# if you've executed sbt assembly previously it will use that instead.
28+
export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties"
29+
ags="$@ generate -t modules/swagger-codegen/src/main/resources/retrofit -i modules/swagger-codegen/src/test/resources/2_0/petstore.json -l retrofit -o samples/client/petstore/retrofit"
30+
31+
java $JAVA_OPTS -jar $executable $ags

modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/CodegenOperation.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
public class CodegenOperation {
88
public Boolean hasConsumes, hasProduces, hasParams, returnTypeIsPrimitive,
99
returnSimpleType, subresourceOperation, isMapContainer, isListContainer,
10-
hasMore = Boolean.TRUE;
10+
hasMore = Boolean.TRUE, isMultipart;
1111
public String path, operationId, returnType, httpMethod, returnBaseType,
1212
returnContainer, summary, notes, baseName, defaultResponse;
1313

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
package com.wordnik.swagger.codegen.languages;
2+
3+
import com.wordnik.swagger.codegen.*;
4+
import com.wordnik.swagger.models.Operation;
5+
import com.wordnik.swagger.models.properties.*;
6+
7+
import java.util.*;
8+
import java.io.File;
9+
10+
public class RetrofitClientCodegen extends DefaultCodegen implements CodegenConfig {
11+
protected String invokerPackage = "io.swagger.client";
12+
protected String groupId = "io.swagger";
13+
protected String artifactId = "swagger-java-client";
14+
protected String artifactVersion = "1.0.0";
15+
protected String sourceFolder = "src/main/java";
16+
17+
public CodegenType getTag() {
18+
return CodegenType.CLIENT;
19+
}
20+
21+
public String getName() {
22+
return "retrofit";
23+
}
24+
25+
public String getHelp() {
26+
return "Generates a Retrofit client library.";
27+
}
28+
29+
public RetrofitClientCodegen() {
30+
super();
31+
outputFolder = "generated-code/java";
32+
modelTemplateFiles.put("model.mustache", ".java");
33+
apiTemplateFiles.put("api.mustache", ".java");
34+
templateDir = "retrofit";
35+
apiPackage = "io.swagger.client.api";
36+
modelPackage = "io.swagger.client.model";
37+
38+
reservedWords = new HashSet<String> (
39+
Arrays.asList(
40+
"abstract", "continue", "for", "new", "switch", "assert",
41+
"default", "if", "package", "synchronized", "boolean", "do", "goto", "private",
42+
"this", "break", "double", "implements", "protected", "throw", "byte", "else",
43+
"import", "public", "throws", "case", "enum", "instanceof", "return", "transient",
44+
"catch", "extends", "int", "short", "try", "char", "final", "interface", "static",
45+
"void", "class", "finally", "long", "strictfp", "volatile", "const", "float",
46+
"native", "super", "while")
47+
);
48+
49+
additionalProperties.put("invokerPackage", invokerPackage);
50+
additionalProperties.put("groupId", groupId);
51+
additionalProperties.put("artifactId", artifactId);
52+
additionalProperties.put("artifactVersion", artifactVersion);
53+
54+
supportingFiles.add(new SupportingFile("pom.mustache", "", "pom.xml"));
55+
supportingFiles.add(new SupportingFile("service.mustache",
56+
(sourceFolder + File.separator + invokerPackage).replace(".", java.io.File.separator), "ServiceGenerator.java"));
57+
58+
languageSpecificPrimitives = new HashSet<String>(
59+
Arrays.asList(
60+
"String",
61+
"boolean",
62+
"Boolean",
63+
"Double",
64+
"Integer",
65+
"Long",
66+
"Float",
67+
"Object")
68+
);
69+
instantiationTypes.put("array", "ArrayList");
70+
instantiationTypes.put("map", "HashMap");
71+
}
72+
73+
@Override
74+
public String escapeReservedWord(String name) {
75+
return "_" + name;
76+
}
77+
78+
@Override
79+
public String apiFileFolder() {
80+
return outputFolder + "/" + sourceFolder + "/" + apiPackage().replace('.', File.separatorChar);
81+
}
82+
83+
public String modelFileFolder() {
84+
return outputFolder + "/" + sourceFolder + "/" + modelPackage().replace('.', File.separatorChar);
85+
}
86+
87+
@Override
88+
public String toVarName(String name) {
89+
// replace - with _ e.g. created-at => created_at
90+
name = name.replaceAll("-", "_");
91+
92+
// if it's all uppper case, do nothing
93+
if (name.matches("^[A-Z_]*$"))
94+
return name;
95+
96+
// camelize (lower first character) the variable name
97+
// pet_id => petId
98+
name = camelize(name, true);
99+
100+
// for reserved word or word starting with number, append _
101+
if(reservedWords.contains(name) || name.matches("^\\d.*"))
102+
name = escapeReservedWord(name);
103+
104+
return name;
105+
}
106+
107+
@Override
108+
public String toParamName(String name) {
109+
// should be the same as variable name
110+
return toVarName(name);
111+
}
112+
113+
@Override
114+
public String toModelName(String name) {
115+
// model name cannot use reserved keyword, e.g. return
116+
if(reservedWords.contains(name))
117+
throw new RuntimeException(name + " (reserved word) cannot be used as a model name");
118+
119+
// camelize the model name
120+
// phone_number => PhoneNumber
121+
return camelize(name);
122+
}
123+
124+
@Override
125+
public String toModelFilename(String name) {
126+
// should be the same as the model name
127+
return toModelName(name);
128+
}
129+
130+
131+
@Override
132+
public String getTypeDeclaration(Property p) {
133+
if(p instanceof ArrayProperty) {
134+
ArrayProperty ap = (ArrayProperty) p;
135+
Property inner = ap.getItems();
136+
return getSwaggerType(p) + "<" + getTypeDeclaration(inner) + ">";
137+
}
138+
else if (p instanceof MapProperty) {
139+
MapProperty mp = (MapProperty) p;
140+
Property inner = mp.getAdditionalProperties();
141+
142+
return getSwaggerType(p) + "<String, " + getTypeDeclaration(inner) + ">";
143+
}
144+
return super.getTypeDeclaration(p);
145+
}
146+
147+
@Override
148+
public String getSwaggerType(Property p) {
149+
String swaggerType = super.getSwaggerType(p);
150+
String type = null;
151+
if(typeMapping.containsKey(swaggerType)) {
152+
type = typeMapping.get(swaggerType);
153+
if(languageSpecificPrimitives.contains(type))
154+
return toModelName(type);
155+
}
156+
else
157+
type = swaggerType;
158+
return toModelName(type);
159+
}
160+
161+
@Override
162+
public String toOperationId(String operationId) {
163+
// method name cannot use reserved keyword, e.g. return
164+
if(reservedWords.contains(operationId))
165+
throw new RuntimeException(operationId + " (reserved word) cannot be used as method name");
166+
167+
return camelize(operationId, true);
168+
}
169+
170+
public Map<String, Object> postProcessOperations(Map<String, Object> objs) {
171+
Map<String, Object> operations = (Map<String, Object>)objs.get("operations");
172+
if(operations != null) {
173+
List<CodegenOperation> ops = (List<CodegenOperation>) operations.get("operation");
174+
for(CodegenOperation operation : ops) {
175+
if (operation.hasConsumes == Boolean.TRUE) {
176+
Map<String, String> firstType = operation.consumes.get(0);
177+
if (firstType != null) {
178+
if ("multipart/form-data".equals(firstType.get("mediaType"))) {
179+
operation.isMultipart = Boolean.TRUE;
180+
}
181+
}
182+
}
183+
if(operation.returnType == null) {
184+
operation.returnType = "Void";
185+
}
186+
}
187+
}
188+
return objs;
189+
}
190+
}

modules/swagger-codegen/src/main/resources/META-INF/services/com.wordnik.swagger.codegen.CodegenConfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ com.wordnik.swagger.codegen.languages.PhpClientCodegen
1010
com.wordnik.swagger.codegen.languages.PythonClientCodegen
1111
com.wordnik.swagger.codegen.languages.Python3ClientCodegen
1212
com.wordnik.swagger.codegen.languages.Qt5CPPGenerator
13+
com.wordnik.swagger.codegen.languages.RetrofitClientCodegen
1314
com.wordnik.swagger.codegen.languages.RubyClientCodegen
1415
com.wordnik.swagger.codegen.languages.ScalaClientCodegen
1516
com.wordnik.swagger.codegen.languages.ScalatraServerCodegen
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package {{package}};
2+
3+
import {{modelPackage}}.*;
4+
5+
import retrofit.http.*;
6+
import retrofit.mime.*;
7+
import java.util.*;
8+
9+
{{#imports}}import {{import}};
10+
{{/imports}}
11+
12+
{{#operations}}
13+
public interface {{classname}} {
14+
{{#operation}}
15+
/**
16+
* {{summary}}
17+
* {{notes}}
18+
{{#allParams}} * @param {{paramName}} {{description}}
19+
{{/allParams}} * @return {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}}
20+
*/
21+
{{#formParams}}{{#-first}}
22+
{{#isMultipart}}@Multipart{{/isMultipart}}{{^isMultipart}}@FormUrlEncoded{{/isMultipart}}{{/-first}}{{/formParams}}
23+
@{{httpMethod}}("{{path}}")
24+
{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Object{{/returnType}} {{nickname}}({{^allParams}});{{/allParams}}
25+
{{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{#hasMore}},{{/hasMore}}{{^hasMore}}
26+
);{{/hasMore}}{{/allParams}}
27+
{{/operation}}
28+
}
29+
{{/operations}}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{{#isBodyParam}}@Body {{{dataType}}} {{paramName}}{{/isBodyParam}}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{{#isFormParam}}{{#notFile}}{{#isMultipart}}@Part{{/isMultipart}}{{^isMultipart}}@Field{{/isMultipart}}("{{paramName}}") {{{dataType}}} {{paramName}}{{/notFile}}{{#isFile}}{{#isMultipart}}@Part{{/isMultipart}}{{^isMultipart}}@Field{{/isMultipart}}("{{paramName}}") TypedFile {{paramName}}{{/isFile}}{{/isFormParam}}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{{#isHeaderParam}}@Header("{{baseName}}") {{{dataType}}} {{paramName}}{{/isHeaderParam}}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package {{package}};
2+
3+
{{#imports}}import {{import}};
4+
{{/imports}}
5+
6+
import com.wordnik.swagger.annotations.*;
7+
import com.google.gson.annotations.SerializedName;
8+
{{#models}}
9+
10+
{{#model}}{{#description}}
11+
/**
12+
* {{description}}
13+
**/{{/description}}
14+
@ApiModel(description = "{{{description}}}")
15+
public class {{classname}} {{#parent}}extends {{{parent}}}{{/parent}} {
16+
{{#vars}}{{#isEnum}}
17+
public enum {{datatypeWithEnum}} {
18+
{{#allowableValues}}{{#values}} {{.}}, {{/values}}{{/allowableValues}}
19+
};{{/isEnum}}
20+
21+
/**{{#description}}
22+
* {{{description}}}{{/description}}{{#minimum}}
23+
* minimum: {{minimum}}{{/minimum}}{{#maximum}}
24+
* maximum: {{maximum}}{{/maximum}}
25+
**/
26+
@ApiModelProperty({{#required}}required = {{required}}, {{/required}}value = "{{{description}}}")
27+
@SerializedName("{{baseName}}"){{#isEnum}}
28+
private {{{datatypeWithEnum}}} {{name}} = {{{defaultValue}}};{{/isEnum}}{{^isEnum}}
29+
private {{{datatype}}} {{name}} = {{{defaultValue}}};{{/isEnum}}{{/vars}}
30+
31+
{{#vars}}
32+
public {{{datatypeWithEnum}}} {{getter}}() {
33+
return {{name}};
34+
}
35+
public void {{setter}}({{{datatypeWithEnum}}} {{name}}) {
36+
this.{{name}} = {{name}};
37+
}
38+
{{/vars}}
39+
@Override
40+
public String toString() {
41+
StringBuilder sb = new StringBuilder();
42+
sb.append("class {{classname}} {\n");
43+
{{#parent}}sb.append(" " + super.toString()).append("\n");{{/parent}}
44+
{{#vars}}sb.append(" {{name}}: ").append({{name}}).append("\n");
45+
{{/vars}}sb.append("}\n");
46+
return sb.toString();
47+
}
48+
}
49+
{{/model}}
50+
{{/models}}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{{#isPathParam}}@Path("{{baseName}}") {{{dataType}}} {{paramName}}{{/isPathParam}}

0 commit comments

Comments
 (0)