|
|
|
|
@@ -30,6 +30,7 @@ public class GoServerCodegen extends DefaultCodegen implements CodegenConfig {
|
|
|
|
|
|
|
|
|
|
private static final Logger LOGGER = LoggerFactory.getLogger(GoServerCodegen.class);
|
|
|
|
|
|
|
|
|
|
protected String packageName = "swagger";
|
|
|
|
|
protected String apiVersion = "1.0.0";
|
|
|
|
|
protected int serverPort = 8080;
|
|
|
|
|
protected String projectName = "swagger-server";
|
|
|
|
|
@@ -47,7 +48,9 @@ public class GoServerCodegen extends DefaultCodegen implements CodegenConfig {
|
|
|
|
|
* for multiple files for model, just put another entry in the `modelTemplateFiles` with
|
|
|
|
|
* a different extension
|
|
|
|
|
*/
|
|
|
|
|
modelTemplateFiles.clear();
|
|
|
|
|
modelTemplateFiles.put(
|
|
|
|
|
"model.mustache",
|
|
|
|
|
".go");
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Api classes. You can write classes for each Api file with the apiTemplateFiles map.
|
|
|
|
|
@@ -55,7 +58,7 @@ public class GoServerCodegen extends DefaultCodegen implements CodegenConfig {
|
|
|
|
|
* class
|
|
|
|
|
*/
|
|
|
|
|
apiTemplateFiles.put(
|
|
|
|
|
"controller.mustache", // the template to use
|
|
|
|
|
"controller-api.mustache", // the template to use
|
|
|
|
|
".go"); // the extension for each file to write
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
@@ -78,8 +81,7 @@ public class GoServerCodegen extends DefaultCodegen implements CodegenConfig {
|
|
|
|
|
"case", "defer", "go", "map", "struct",
|
|
|
|
|
"chan", "else", "goto", "package", "switch",
|
|
|
|
|
"const", "fallthrough", "if", "range", "type",
|
|
|
|
|
"continue", "for", "import", "return", "var", "error", "ApiResponse",
|
|
|
|
|
"nil")
|
|
|
|
|
"continue", "for", "import", "return", "var", "error", "nil")
|
|
|
|
|
// Added "error" as it's used so frequently that it may as well be a keyword
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
@@ -143,6 +145,19 @@ public class GoServerCodegen extends DefaultCodegen implements CodegenConfig {
|
|
|
|
|
cliOptions.add(new CliOption(CodegenConstants.HIDE_GENERATION_TIMESTAMP, "hides the timestamp when files were generated")
|
|
|
|
|
.defaultValue(Boolean.TRUE.toString()));
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void processOpts() {
|
|
|
|
|
super.processOpts();
|
|
|
|
|
|
|
|
|
|
if (additionalProperties.containsKey(CodegenConstants.PACKAGE_NAME)) {
|
|
|
|
|
setPackageName((String) additionalProperties.get(CodegenConstants.PACKAGE_NAME));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
setPackageName("swagger");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Additional Properties. These values can be passed to the templates and
|
|
|
|
|
* are available in models, apis, and supporting files
|
|
|
|
|
@@ -150,19 +165,20 @@ public class GoServerCodegen extends DefaultCodegen implements CodegenConfig {
|
|
|
|
|
additionalProperties.put("apiVersion", apiVersion);
|
|
|
|
|
additionalProperties.put("serverPort", serverPort);
|
|
|
|
|
additionalProperties.put("apiPath", apiPath);
|
|
|
|
|
additionalProperties.put(CodegenConstants.PACKAGE_NAME, packageName);
|
|
|
|
|
|
|
|
|
|
modelPackage = packageName;
|
|
|
|
|
apiPackage = packageName;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Supporting Files. You can write single files for the generator with the
|
|
|
|
|
* entire object tree available. If the input file has a suffix of `.mustache
|
|
|
|
|
* it will be processed by the template engine. Otherwise, it will be copied
|
|
|
|
|
*/
|
|
|
|
|
supportingFiles.add(new SupportingFile("swagger.mustache",
|
|
|
|
|
"api",
|
|
|
|
|
"swagger.yaml")
|
|
|
|
|
);
|
|
|
|
|
supportingFiles.add(new SupportingFile("swagger.mustache", "api", "swagger.yaml"));
|
|
|
|
|
supportingFiles.add(new SupportingFile("main.mustache", "", "main.go"));
|
|
|
|
|
supportingFiles.add(new SupportingFile("routers.mustache", apiPath, "routers.go"));
|
|
|
|
|
supportingFiles.add(new SupportingFile("logger.mustache", apiPath, "logger.go"));
|
|
|
|
|
supportingFiles.add(new SupportingFile("app.mustache", apiPath, "app.yaml"));
|
|
|
|
|
writeOptional(outputFolder, new SupportingFile("README.mustache", apiPath, "README.md"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -205,14 +221,6 @@ public class GoServerCodegen extends DefaultCodegen implements CodegenConfig {
|
|
|
|
|
"it will also generate service classes--which you can disable with the `-Dnoservice` environment variable.";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public String toApiName(String name) {
|
|
|
|
|
if (name.length() == 0) {
|
|
|
|
|
return "DefaultController";
|
|
|
|
|
}
|
|
|
|
|
return initialCaps(name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Escapes a reserved word as defined in the `reservedWords` array. Handle escaping
|
|
|
|
|
* those terms here. This logic is only called if a variable matches the reserved words
|
|
|
|
|
@@ -220,11 +228,23 @@ public class GoServerCodegen extends DefaultCodegen implements CodegenConfig {
|
|
|
|
|
* @return the escaped term
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
public String escapeReservedWord(String name) {
|
|
|
|
|
public String escapeReservedWord(String name)
|
|
|
|
|
{
|
|
|
|
|
// Can't start with an underscore, as our fields need to start with an
|
|
|
|
|
// UppercaseLetter so that Go treats them as public/visible.
|
|
|
|
|
|
|
|
|
|
// Options?
|
|
|
|
|
// - MyName
|
|
|
|
|
// - AName
|
|
|
|
|
// - TheName
|
|
|
|
|
// - XName
|
|
|
|
|
// - X_Name
|
|
|
|
|
// ... or maybe a suffix?
|
|
|
|
|
// - Name_ ... think this will work.
|
|
|
|
|
if(this.reservedWordsMappings().containsKey(name)) {
|
|
|
|
|
return this.reservedWordsMappings().get(name);
|
|
|
|
|
}
|
|
|
|
|
return "_" + name; // add an underscore to the name
|
|
|
|
|
return camelize(name) + '_';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@@ -236,6 +256,46 @@ public class GoServerCodegen extends DefaultCodegen implements CodegenConfig {
|
|
|
|
|
return outputFolder + File.separator + apiPackage().replace('.', File.separatorChar);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public String modelFileFolder() {
|
|
|
|
|
return outputFolder + File.separator + apiPackage().replace('.', File.separatorChar);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public String toVarName(String name) {
|
|
|
|
|
// replace - with _ e.g. created-at => created_at
|
|
|
|
|
name = sanitizeName(name.replaceAll("-", "_"));
|
|
|
|
|
|
|
|
|
|
// if it's all uppper case, do nothing
|
|
|
|
|
if (name.matches("^[A-Z_]*$"))
|
|
|
|
|
return name;
|
|
|
|
|
|
|
|
|
|
// camelize (lower first character) the variable name
|
|
|
|
|
// pet_id => PetId
|
|
|
|
|
name = camelize(name);
|
|
|
|
|
|
|
|
|
|
// for reserved word or word starting with number, append _
|
|
|
|
|
if (isReservedWord(name))
|
|
|
|
|
name = escapeReservedWord(name);
|
|
|
|
|
|
|
|
|
|
// for reserved word or word starting with number, append _
|
|
|
|
|
if (name.matches("^\\d.*"))
|
|
|
|
|
name = "Var" + name;
|
|
|
|
|
|
|
|
|
|
return name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public String toParamName(String name) {
|
|
|
|
|
// params should be lowerCamelCase. E.g. "person Person", instead of
|
|
|
|
|
// "Person Person".
|
|
|
|
|
//
|
|
|
|
|
// REVISIT: Actually, for idiomatic go, the param name should
|
|
|
|
|
// really should just be a letter, e.g. "p Person"), but we'll get
|
|
|
|
|
// around to that some other time... Maybe.
|
|
|
|
|
return camelize(toVarName(name), true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public String toModelName(String name) {
|
|
|
|
|
// camelize the model name
|
|
|
|
|
@@ -243,36 +303,67 @@ public class GoServerCodegen extends DefaultCodegen implements CodegenConfig {
|
|
|
|
|
return camelize(toModelFilename(name));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public String toOperationId(String operationId) {
|
|
|
|
|
// method name cannot use reserved keyword, e.g. return
|
|
|
|
|
if (isReservedWord(operationId)) {
|
|
|
|
|
LOGGER.warn(operationId + " (reserved word) cannot be used as method name. Renamed to " + camelize(sanitizeName("call_" + operationId)));
|
|
|
|
|
operationId = "call_" + operationId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return camelize(operationId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public String toModelFilename(String name) {
|
|
|
|
|
if (!StringUtils.isEmpty(modelNamePrefix)) {
|
|
|
|
|
name = modelNamePrefix + name;
|
|
|
|
|
name = modelNamePrefix + "_" + name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!StringUtils.isEmpty(modelNameSuffix)) {
|
|
|
|
|
name = name + modelNameSuffix;
|
|
|
|
|
name = name + "_" + modelNameSuffix;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
name = sanitizeName(name);
|
|
|
|
|
|
|
|
|
|
// model name cannot use reserved keyword, e.g. return
|
|
|
|
|
if (isReservedWord(name)) {
|
|
|
|
|
LOGGER.warn(name + " (reserved word) cannot be used as model name. Renamed to " + camelize("model_" + name));
|
|
|
|
|
LOGGER.warn(name + " (reserved word) cannot be used as model name. Renamed to " + ("model_" + name));
|
|
|
|
|
name = "model_" + name; // e.g. return => ModelReturn (after camelize)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return camelize(name);
|
|
|
|
|
// model name starts with number
|
|
|
|
|
if (name.matches("^\\d.*")) {
|
|
|
|
|
LOGGER.warn(name + " (model name starts with number) cannot be used as model name. Renamed to " + ("model_" + name));
|
|
|
|
|
name = "model_" + name; // e.g. 200Response => Model200Response (after camelize)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return underscore(name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public String toApiFilename(String name) {
|
|
|
|
|
// replace - with _ e.g. created-at => created_at
|
|
|
|
|
name = name.replaceAll("-", "_"); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'.
|
|
|
|
|
|
|
|
|
|
// e.g. PetApi.go => pet_api.go
|
|
|
|
|
return underscore(name) + "_api";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Overrides postProcessParameter to add a vendor extension "x-exportParamName".
|
|
|
|
|
* This is useful when paramName starts with a lowercase letter, but we need that
|
|
|
|
|
* param to be exportable (starts with an Uppercase letter).
|
|
|
|
|
*
|
|
|
|
|
* @param parameter CodegenParameter object to be processed.
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
public void postProcessParameter(CodegenParameter parameter){
|
|
|
|
|
|
|
|
|
|
// Give the base class a chance to process
|
|
|
|
|
super.postProcessParameter(parameter);
|
|
|
|
|
|
|
|
|
|
char firstChar = parameter.paramName.charAt(0);
|
|
|
|
|
|
|
|
|
|
if (Character.isUpperCase(firstChar)) {
|
|
|
|
|
// First char is already uppercase, just use paramName.
|
|
|
|
|
parameter.vendorExtensions.put("x-exportParamName", parameter.paramName);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// It's a lowercase first char, let's convert it to uppercase
|
|
|
|
|
StringBuilder sb = new StringBuilder(parameter.paramName);
|
|
|
|
|
sb.setCharAt(0, Character.toUpperCase(firstChar));
|
|
|
|
|
parameter.vendorExtensions.put("x-exportParamName", sb.toString());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
@@ -323,14 +414,127 @@ public class GoServerCodegen extends DefaultCodegen implements CodegenConfig {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public String toApiFilename(String name) {
|
|
|
|
|
// replace - with _ e.g. created-at => created_at
|
|
|
|
|
name = name.replaceAll("-", "_"); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'.
|
|
|
|
|
public String toOperationId(String operationId) {
|
|
|
|
|
String sanitizedOperationId = sanitizeName(operationId);
|
|
|
|
|
|
|
|
|
|
// e.g. PetApi.go => pet_api.go
|
|
|
|
|
return underscore(name);
|
|
|
|
|
// method name cannot use reserved keyword, e.g. return
|
|
|
|
|
if (isReservedWord(sanitizedOperationId)) {
|
|
|
|
|
LOGGER.warn(operationId + " (reserved word) cannot be used as method name. Renamed to " + camelize("call_" + operationId));
|
|
|
|
|
sanitizedOperationId = "call_" + sanitizedOperationId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return camelize(sanitizedOperationId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Map<String, Object> postProcessOperations(Map<String, Object> objs) {
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
|
Map<String, Object> objectMap = (Map<String, Object>) objs.get("operations");
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
|
List<CodegenOperation> operations = (List<CodegenOperation>) objectMap.get("operation");
|
|
|
|
|
for (CodegenOperation operation : operations) {
|
|
|
|
|
// http method verb conversion (e.g. PUT => Put)
|
|
|
|
|
operation.httpMethod = camelize(operation.httpMethod.toLowerCase());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// remove model imports to avoid error
|
|
|
|
|
List<Map<String, String>> imports = (List<Map<String, String>>) objs.get("imports");
|
|
|
|
|
if (imports == null)
|
|
|
|
|
return objs;
|
|
|
|
|
|
|
|
|
|
Iterator<Map<String, String>> iterator = imports.iterator();
|
|
|
|
|
while (iterator.hasNext()) {
|
|
|
|
|
String _import = iterator.next().get("import");
|
|
|
|
|
if (_import.startsWith(apiPackage()))
|
|
|
|
|
iterator.remove();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if their is a return type, import encoding/json
|
|
|
|
|
for (CodegenOperation operation : operations) {
|
|
|
|
|
if(operation.returnBaseType != null ) {
|
|
|
|
|
imports.add(createMapping("import", "encoding/json"));
|
|
|
|
|
break; //just need to import once
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// this will only import "fmt" if there are items in pathParams
|
|
|
|
|
for (CodegenOperation operation : operations) {
|
|
|
|
|
if(operation.pathParams != null && operation.pathParams.size() > 0) {
|
|
|
|
|
imports.add(createMapping("import", "fmt"));
|
|
|
|
|
break; //just need to import once
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// recursively add import for mapping one type to multiple imports
|
|
|
|
|
List<Map<String, String>> recursiveImports = (List<Map<String, String>>) objs.get("imports");
|
|
|
|
|
if (recursiveImports == null)
|
|
|
|
|
return objs;
|
|
|
|
|
|
|
|
|
|
ListIterator<Map<String, String>> listIterator = imports.listIterator();
|
|
|
|
|
while (listIterator.hasNext()) {
|
|
|
|
|
String _import = listIterator.next().get("import");
|
|
|
|
|
// if the import package happens to be found in the importMapping (key)
|
|
|
|
|
// add the corresponding import package to the list
|
|
|
|
|
if (importMapping.containsKey(_import)) {
|
|
|
|
|
listIterator.add(createMapping("import", importMapping.get(_import)));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return objs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Map<String, Object> postProcessSupportingFileData(Map<String, Object> objs) {
|
|
|
|
|
Swagger swagger = (Swagger)objs.get("swagger");
|
|
|
|
|
if(swagger != null) {
|
|
|
|
|
try {
|
|
|
|
|
objs.put("swagger-yaml", Yaml.mapper().writeValueAsString(swagger));
|
|
|
|
|
} catch (JsonProcessingException e) {
|
|
|
|
|
LOGGER.error(e.getMessage(), e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return super.postProcessSupportingFileData(objs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Map<String, Object> postProcessModels(Map<String, Object> objs) {
|
|
|
|
|
// remove model imports to avoid error
|
|
|
|
|
List<Map<String, String>> imports = (List<Map<String, String>>) objs.get("imports");
|
|
|
|
|
final String prefix = modelPackage();
|
|
|
|
|
Iterator<Map<String, String>> iterator = imports.iterator();
|
|
|
|
|
while (iterator.hasNext()) {
|
|
|
|
|
String _import = iterator.next().get("import");
|
|
|
|
|
if (_import.startsWith(prefix))
|
|
|
|
|
iterator.remove();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// recursively add import for mapping one type to multiple imports
|
|
|
|
|
List<Map<String, String>> recursiveImports = (List<Map<String, String>>) objs.get("imports");
|
|
|
|
|
if (recursiveImports == null)
|
|
|
|
|
return objs;
|
|
|
|
|
|
|
|
|
|
ListIterator<Map<String, String>> listIterator = imports.listIterator();
|
|
|
|
|
while (listIterator.hasNext()) {
|
|
|
|
|
String _import = listIterator.next().get("import");
|
|
|
|
|
// if the import package happens to be found in the importMapping (key)
|
|
|
|
|
// add the corresponding import package to the list
|
|
|
|
|
if (importMapping.containsKey(_import)) {
|
|
|
|
|
listIterator.add(createMapping("import", importMapping.get(_import)));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return postProcessModelsEnum(objs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
protected boolean needToImport(String type) {
|
|
|
|
|
return !defaultIncludes.contains(type)
|
|
|
|
|
&& !languageSpecificPrimitives.contains(type);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setPackageName(String packageName) {
|
|
|
|
|
this.packageName = packageName;
|
|
|
|
|
}
|
|
|
|
|
@Override
|
|
|
|
|
public String escapeQuotationMark(String input) {
|
|
|
|
|
// remove " to avoid code injection
|
|
|
|
|
@@ -342,12 +546,19 @@ public class GoServerCodegen extends DefaultCodegen implements CodegenConfig {
|
|
|
|
|
return input.replace("*/", "*_/").replace("/*", "/_*");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Map<String, String> createMapping(String key, String value){
|
|
|
|
|
Map<String, String> customImport = new HashMap<String, String>();
|
|
|
|
|
customImport.put(key, value);
|
|
|
|
|
|
|
|
|
|
return customImport;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public String toEnumValue(String value, String datatype) {
|
|
|
|
|
if ("int".equals(datatype) || "double".equals(datatype) || "float".equals(datatype)) {
|
|
|
|
|
return value;
|
|
|
|
|
} else {
|
|
|
|
|
return "\'" + escapeText(value) + "\'";
|
|
|
|
|
return escapeText(value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -402,9 +613,4 @@ public class GoServerCodegen extends DefaultCodegen implements CodegenConfig {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Map<String, Object> postProcessModels(Map<String, Object> objs) {
|
|
|
|
|
// process enum in models
|
|
|
|
|
return postProcessModelsEnum(objs);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|