moved post process model method to an util class and tweaked its references.

This commit is contained in:
Hugo Mercado
2017-11-23 23:41:28 -05:00
parent c014102516
commit 1389ce080c
9 changed files with 218 additions and 174 deletions

View File

@@ -4,6 +4,7 @@ import com.github.jknack.handlebars.Helper;
import com.google.common.base.Function;
import com.google.common.collect.Lists;
import com.samskivert.mustache.Mustache.Compiler;
import io.swagger.codegen.utils.ModelUtils;
import io.swagger.oas.models.OpenAPI;
import io.swagger.oas.models.Operation;
import io.swagger.oas.models.headers.Header;
@@ -59,6 +60,10 @@ import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static io.swagger.codegen.utils.ModelUtils.processCodegenModels;
import static io.swagger.codegen.utils.ModelUtils.processModelEnums;
import static io.swagger.codegen.utils.ModelUtils.updateCodegenPropertyEnum;
public class DefaultCodegen implements CodegenConfig {
protected static final Logger LOGGER = LoggerFactory.getLogger(DefaultCodegen.class);
public static final String DEFAULT_CONTENT_TYPE = "application/json";
@@ -172,11 +177,11 @@ public class DefaultCodegen implements CodegenConfig {
// override with any special post-processing for all models
@SuppressWarnings({ "static-method", "unchecked" })
public Map<String, Object> postProcessAllModels(Map<String, Object> objs) {
public Map<String, Object> postProcessAllModels(Map<String, Object> processedModels) {
if (supportsInheritance) {
// Index all CodegenModels by model name.
Map<String, CodegenModel> allModels = new HashMap<String, CodegenModel>();
for (Entry<String, Object> entry : objs.entrySet()) {
Map<String, CodegenModel> allModels = new HashMap<>();
for (Map.Entry<String, Object> entry : processedModels.entrySet()) {
String modelName = toModelName(entry.getKey());
Map<String, Object> inner = (Map<String, Object>) entry.getValue();
List<Map<String, Object>> models = (List<Map<String, Object>>) inner.get("models");
@@ -185,41 +190,9 @@ public class DefaultCodegen implements CodegenConfig {
allModels.put(modelName, cm);
}
}
// Fix up all parent and interface CodegenModel references.
for (CodegenModel cm : allModels.values()) {
if (cm.parent != null) {
cm.parentModel = allModels.get(cm.parent);
}
if (cm.interfaces != null && !cm.interfaces.isEmpty()) {
cm.interfaceModels = new ArrayList<CodegenModel>(cm.interfaces.size());
for (String intf : cm.interfaces) {
CodegenModel intfModel = allModels.get(intf);
if (intfModel != null) {
cm.interfaceModels.add(intfModel);
}
}
}
}
// Let parent know about all its children
for (String name : allModels.keySet()) {
CodegenModel cm = allModels.get(name);
CodegenModel parent = allModels.get(cm.parent);
// if a discriminator exists on the parent, don't add this child to the inheritance heirarchy
// TODO Determine what to do if the parent discriminator name == the grandparent discriminator name
while (parent != null) {
if (parent.children == null) {
parent.children = new ArrayList<CodegenModel>();
}
parent.children.add(cm);
if (parent.discriminator == null) {
parent = allModels.get(parent.parent);
} else {
parent = null;
}
}
}
processCodegenModels(allModels);;
}
return objs;
return processedModels;
}
// override with any special post-processing
@@ -235,64 +208,10 @@ public class DefaultCodegen implements CodegenConfig {
* @return maps of models with better enum support
*/
public Map<String, Object> postProcessModelsEnum(Map<String, Object> objs) {
List<Object> models = (List<Object>) objs.get("models");
for (Object _mo : models) {
Map<String, Object> mo = (Map<String, Object>) _mo;
CodegenModel cm = (CodegenModel) mo.get("model");
// for enum model
if (Boolean.TRUE.equals(cm.isEnum) && cm.allowableValues != null) {
Map<String, Object> allowableValues = cm.allowableValues;
List<Object> values = (List<Object>) allowableValues.get("values");
List<Map<String, String>> enumVars = new ArrayList<Map<String, String>>();
String commonPrefix = findCommonPrefixOfVars(values);
int truncateIdx = commonPrefix.length();
for (Object value : values) {
Map<String, String> enumVar = new HashMap<String, String>();
String enumName;
if (truncateIdx == 0) {
enumName = value.toString();
} else {
enumName = value.toString().substring(truncateIdx);
if ("".equals(enumName)) {
enumName = value.toString();
}
}
enumVar.put("name", toEnumVarName(enumName, cm.dataType));
enumVar.put("value", toEnumValue(value.toString(), cm.dataType));
enumVars.add(enumVar);
}
cm.allowableValues.put("enumVars", enumVars);
}
// update codegen property enum with proper naming convention
// and handling of numbers, special characters
for (CodegenProperty var : cm.vars) {
updateCodegenPropertyEnum(var);
}
}
processModelEnums(objs);
return objs;
}
/**
* Returns the common prefix of variables for enum naming
*
* @param vars List of variable names
* @return the common prefix for naming
*/
public String findCommonPrefixOfVars(List<Object> vars) {
try {
String[] listStr = vars.toArray(new String[vars.size()]);
String prefix = StringUtils.getCommonPrefix(listStr);
// exclude trailing characters that should be part of a valid variable
// e.g. ["status-on", "status-off"] => "status-" (not "status-o")
return prefix.replaceAll("[a-zA-Z0-9]+\\z", "");
} catch (ArrayStoreException e) {
return "";
}
}
/**
* Return the enum default value in the language specified format
*
@@ -328,16 +247,7 @@ public class DefaultCodegen implements CodegenConfig {
* @return the sanitized variable name for enum
*/
public String toEnumVarName(String value, String datatype) {
if (value.length() == 0) {
return "EMPTY";
}
String var = value.replaceAll("\\W+", "_").toUpperCase();
if (var.matches("\\d.*")) {
return "_" + var;
} else {
return var;
}
return ModelUtils.toEnumVarName(value);
}
// override with any special post-processing
@@ -3418,65 +3328,6 @@ public class DefaultCodegen implements CodegenConfig {
}
}
/**
* Update codegen property's enum by adding "enumVars" (with name and value)
*
* @param var list of CodegenProperty
*/
public void updateCodegenPropertyEnum(CodegenProperty var) {
Map<String, Object> allowableValues = var.allowableValues;
// handle ArrayProperty
if (var.items != null) {
allowableValues = var.items.allowableValues;
}
if (allowableValues == null) {
return;
}
List<Object> values = (List<Object>) allowableValues.get("values");
if (values == null) {
return;
}
// put "enumVars" map into `allowableValues", including `name` and `value`
List<Map<String, String>> enumVars = new ArrayList<Map<String, String>>();
String commonPrefix = findCommonPrefixOfVars(values);
int truncateIdx = commonPrefix.length();
for (Object value : values) {
Map<String, String> enumVar = new HashMap<String, String>();
String enumName;
if (truncateIdx == 0) {
enumName = value.toString();
} else {
enumName = value.toString().substring(truncateIdx);
if ("".equals(enumName)) {
enumName = value.toString();
}
}
enumVar.put("name", toEnumVarName(enumName, var.datatype));
enumVar.put("value", toEnumValue(value.toString(), var.datatype));
enumVars.add(enumVar);
}
allowableValues.put("enumVars", enumVars);
// handle default value for enum, e.g. available => StatusEnum.AVAILABLE
if (var.defaultValue != null) {
String enumName = null;
for (Map<String, String> enumVar : enumVars) {
if (toEnumValue(var.defaultValue, var.datatype).equals(enumVar.get("value"))) {
enumName = enumVar.get("name");
break;
}
}
if (enumName != null) {
var.defaultValue = toEnumDefaultValue(enumName, var.datatypeWithEnum);
}
}
}
/**
* If the pattern misses the delimiter, add "/" to the beginning and end
* Otherwise, return the original pattern

View File

@@ -16,6 +16,8 @@ import org.slf4j.LoggerFactory;
import java.io.File;
import java.util.*;
import static io.swagger.codegen.utils.ModelUtils.updateCodegenPropertyEnum;
public abstract class AbstractCSharpCodegen extends DefaultCodegen implements CodegenConfig {
protected boolean optionalAssemblyInfoFlag = true;

View File

@@ -1,6 +1,7 @@
package io.swagger.codegen.languages;
import io.swagger.codegen.*;
import io.swagger.codegen.utils.ModelUtils;
import io.swagger.oas.models.OpenAPI;
import io.swagger.oas.models.Operation;
import io.swagger.oas.models.info.Info;
@@ -447,9 +448,8 @@ public class ApexClientCodegen extends AbstractJavaCodegen {
return camelize(classPrefix + super.toApiName(name));
}
@Override
public void updateCodegenPropertyEnum(CodegenProperty var) {
super.updateCodegenPropertyEnum(var);
ModelUtils.updateCodegenPropertyEnum(var);
if (var.isEnum && var.example != null) {
String example = var.example.replace("'", "");
example = toEnumVarName(example, var.datatype);

View File

@@ -8,6 +8,7 @@ import io.swagger.codegen.CodegenProperty;
import io.swagger.codegen.CodegenType;
import io.swagger.codegen.DefaultCodegen;
import io.swagger.codegen.SupportingFile;
import io.swagger.codegen.utils.ModelUtils;
import io.swagger.oas.models.media.ArraySchema;
import io.swagger.oas.models.media.MapSchema;
import io.swagger.oas.models.media.Schema;
@@ -324,7 +325,7 @@ public class DartClientCodegen extends DefaultCodegen implements CodegenConfig {
boolean succes = buildEnumFromVendorExtension(cm) ||
buildEnumFromValues(cm);
for (CodegenProperty var : cm.vars) {
updateCodegenPropertyEnum(var);
ModelUtils.updateCodegenPropertyEnum(var);
}
}
return objs;
@@ -343,7 +344,7 @@ public class DartClientCodegen extends DefaultCodegen implements CodegenConfig {
List<Object> values = (List<Object>) allowableValues.get("values");
List<Map<String, String>> enumVars =
new ArrayList<Map<String, String>>();
String commonPrefix = findCommonPrefixOfVars(values);
String commonPrefix = ModelUtils.findCommonPrefixOfVars(values);
int truncateIdx = commonPrefix.length();
for (Object value : values) {
Map<String, String> enumVar = new HashMap<String, String>();

View File

@@ -7,6 +7,7 @@ import java.io.IOException;
import java.util.*;
import java.util.regex.Pattern;
import io.swagger.codegen.utils.ModelUtils;
import io.swagger.oas.models.OpenAPI;
import io.swagger.oas.models.Operation;
import io.swagger.oas.models.media.ArraySchema;
@@ -570,7 +571,7 @@ public class HaskellHttpClientCodegen extends DefaultCodegen implements CodegenC
return op;
}
public List<CodegenSecurity> fromSecurity(Map<String, SecurityScheme> schemes) {
List<CodegenSecurity> secs = super.fromSecurity(schemes);
for(CodegenSecurity sec : secs) {
@@ -1123,9 +1124,8 @@ public class HaskellHttpClientCodegen extends DefaultCodegen implements CodegenC
return paramNameType;
}
@Override
public void updateCodegenPropertyEnum(CodegenProperty var) {
super.updateCodegenPropertyEnum(var);
ModelUtils.updateCodegenPropertyEnum(var);
if (!genEnums) return;
updateCodegenPropertyEnumValues(var, var.datatypeWithEnum);
}

View File

@@ -1,9 +1,15 @@
package io.swagger.codegen.utils;
import io.swagger.codegen.CodegenConfig;
import io.swagger.codegen.CodegenModel;
import io.swagger.codegen.CodegenProperty;
import io.swagger.oas.models.Operation;
import io.swagger.oas.models.PathItem;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -47,4 +53,182 @@ public class ModelUtils {
pathItem.getOptions()
};
}
public static void processCodegenModels(Map<String, CodegenModel> allModels) {
// Fix up all parent and interface CodegenModel references.
for (CodegenModel codegenModel : allModels.values()) {
if (codegenModel.getParent() != null) {
codegenModel.setParentModel(allModels.get(codegenModel.getParent()));
}
if (codegenModel.getInterfaces() == null || codegenModel.getInterfaces().isEmpty()) {
continue;
}
codegenModel.setInterfaceModels(new ArrayList<CodegenModel>(codegenModel.getInterfaces().size()));
for (String intf : codegenModel.getInterfaces()) {
CodegenModel intfModel = allModels.get(intf);
if (intfModel != null) {
codegenModel.getInterfaceModels().add(intfModel);
}
}
}
// Let parent know about all its children
for (String name : allModels.keySet()) {
CodegenModel codegenModel = allModels.get(name);
CodegenModel parent = allModels.get(codegenModel.getParent());
// if a discriminator exists on the parent, don't add this child to the inheritance heirarchy
// TODO Determine what to do if the parent discriminator name == the grandparent discriminator name
while (parent != null) {
if (parent.getChildren() == null) {
parent.setChildren(new ArrayList<CodegenModel>());
}
parent.getChildren().add(codegenModel);
if (parent.getDiscriminator() == null) {
parent = allModels.get(parent.parent);
} else {
parent = null;
}
}
}
}
public static void processModelEnums(Map<String, Object> objs) {
List<Object> models = (List<Object>) objs.get("models");
for (Object _mo : models) {
Map<String, Object> mo = (Map<String, Object>) _mo;
CodegenModel cm = (CodegenModel) mo.get("model");
// for enum model
if (Boolean.TRUE.equals(cm.isEnum) && cm.allowableValues != null) {
Map<String, Object> allowableValues = cm.allowableValues;
List<Object> values = (List<Object>) allowableValues.get("values");
List<Map<String, String>> enumVars = new ArrayList<Map<String, String>>();
String commonPrefix = findCommonPrefixOfVars(values);
int truncateIdx = commonPrefix.length();
for (Object value : values) {
Map<String, String> enumVar = new HashMap<String, String>();
String enumName;
if (truncateIdx == 0) {
enumName = value.toString();
} else {
enumName = value.toString().substring(truncateIdx);
if ("".equals(enumName)) {
enumName = value.toString();
}
}
enumVar.put("name", toEnumVarName(enumName));
enumVar.put("value", toEnumValue(value.toString(), cm.dataType));
enumVars.add(enumVar);
}
cm.allowableValues.put("enumVars", enumVars);
}
// update codegen property enum with proper naming convention
// and handling of numbers, special characters
for (CodegenProperty var : cm.vars) {
updateCodegenPropertyEnum(var);
}
}
}
/**
* Returns the common prefix of variables for enum naming
*
* @param vars List of variable names
* @return the common prefix for naming
*/
public static String findCommonPrefixOfVars(List<Object> vars) {
try {
String[] listStr = vars.toArray(new String[vars.size()]);
String prefix = StringUtils.getCommonPrefix(listStr);
// exclude trailing characters that should be part of a valid variable
// e.g. ["status-on", "status-off"] => "status-" (not "status-o")
return prefix.replaceAll("[a-zA-Z0-9]+\\z", "");
} catch (ArrayStoreException e) {
return "";
}
}
/**
* Update codegen property's enum by adding "enumVars" (with name and value)
*
* @param var list of CodegenProperty
*/
public static void updateCodegenPropertyEnum(CodegenProperty var) {
Map<String, Object> allowableValues = var.allowableValues;
// handle ArrayProperty
if (var.items != null) {
allowableValues = var.items.allowableValues;
}
if (allowableValues == null) {
return;
}
List<Object> values = (List<Object>) allowableValues.get("values");
if (values == null) {
return;
}
// put "enumVars" map into `allowableValues", including `name` and `value`
List<Map<String, String>> enumVars = new ArrayList<Map<String, String>>();
String commonPrefix = findCommonPrefixOfVars(values);
int truncateIdx = commonPrefix.length();
for (Object value : values) {
Map<String, String> enumVar = new HashMap<String, String>();
String enumName;
if (truncateIdx == 0) {
enumName = value.toString();
} else {
enumName = value.toString().substring(truncateIdx);
if ("".equals(enumName)) {
enumName = value.toString();
}
}
enumVar.put("name", toEnumVarName(enumName));
enumVar.put("value", toEnumValue(value.toString(), var.datatype));
enumVars.add(enumVar);
}
allowableValues.put("enumVars", enumVars);
// handle default value for enum, e.g. available => StatusEnum.AVAILABLE
if (var.defaultValue != null) {
String enumName = null;
for (Map<String, String> enumVar : enumVars) {
if (toEnumValue(var.defaultValue, var.datatype).equals(enumVar.get("value"))) {
enumName = enumVar.get("name");
break;
}
}
if (enumName != null) {
var.defaultValue = String.format("%s.%s", enumName, var.datatypeWithEnum);
}
}
}
public static String toEnumVarName(String value) {
if (value.length() == 0) {
return "EMPTY";
}
String var = value.replaceAll("\\W+", "_").toUpperCase();
if (var.matches("\\d.*")) {
return "_" + var;
} else {
return var;
}
}
private static String toEnumValue(String value, String datatype) {
if ("number".equalsIgnoreCase(datatype)) {
return value;
} else {
value = StringEscapeUtils.unescapeJava(
StringEscapeUtils.escapeJava(value)
.replace("\\/", "/"))
.replaceAll("[\\t\\n\\r]"," ")
.replace("\\", "\\\\")
.replace("\"", "\\\"");
return String.format("\"%s\"", value);
}
}
}

View File

@@ -16,6 +16,8 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import static io.swagger.codegen.utils.ModelUtils.updateCodegenPropertyEnum;
@SuppressWarnings("static-method")
public class JavaScriptModelEnumTest {
@Test(description = "convert a JavaScript model with an enum")
@@ -97,7 +99,7 @@ public class JavaScriptModelEnumTest {
Map<String, Schema> schemas = schema.getProperties();
Schema property = schemas.get("array_enum");
CodegenProperty prope = codegen.fromProperty("array_enum", property);
codegen.updateCodegenPropertyEnum(prope);
updateCodegenPropertyEnum(prope);
Assert.assertEquals(prope.datatypeWithEnum, "[ArrayEnumEnum]");
Assert.assertEquals(prope.enumName, "ArrayEnumEnum");
Assert.assertTrue(prope.isEnum);
@@ -130,7 +132,7 @@ public class JavaScriptModelEnumTest {
Map<String, Schema> schemas = schema.getProperties();
Schema property = schemas.get("enum_integer");
CodegenProperty prope = codegen.fromProperty("enum_integer", property);
codegen.updateCodegenPropertyEnum(prope);
updateCodegenPropertyEnum(prope);
Assert.assertEquals(prope.datatypeWithEnum, "EnumIntegerEnum");
Assert.assertEquals(prope.enumName, "EnumIntegerEnum");
Assert.assertTrue(prope.isEnum);

View File

@@ -23,6 +23,8 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import static io.swagger.codegen.utils.ModelUtils.updateCodegenPropertyEnum;
@SuppressWarnings("static-method")
public class PhpModelTest {
@@ -284,7 +286,7 @@ public class PhpModelTest {
Schema property = (Schema) schema.getProperties().get("array_enum");
CodegenProperty prope = codegen.fromProperty("array_enum", property);
codegen.updateCodegenPropertyEnum(prope);
updateCodegenPropertyEnum(prope);
Assert.assertEquals(prope.datatypeWithEnum, "ARRAY_ENUM[]");
Assert.assertEquals(prope.enumName, "ARRAY_ENUM");
Assert.assertTrue(prope.isEnum);
@@ -316,7 +318,7 @@ public class PhpModelTest {
Schema property = (Schema) schema.getProperties().get("enum_integer");
CodegenProperty prope = codegen.fromProperty("enum_integer", property);
codegen.updateCodegenPropertyEnum(prope);
updateCodegenPropertyEnum(prope);
Assert.assertEquals(prope.datatypeWithEnum, "ENUM_INTEGER");
Assert.assertEquals(prope.enumName, "ENUM_INTEGER");
Assert.assertTrue(prope.isEnum);

View File

@@ -20,6 +20,8 @@ import org.testng.annotations.Test;
import java.util.Arrays;
import java.util.HashMap;
import static io.swagger.codegen.utils.ModelUtils.updateCodegenPropertyEnum;
@SuppressWarnings("static-method")
public class TypeScriptFetchModelTest {
@@ -204,7 +206,7 @@ public class TypeScriptFetchModelTest {
Schema property = (Schema) schema.getProperties().get("array_enum");
CodegenProperty prope = codegen.fromProperty("array_enum", property);
codegen.updateCodegenPropertyEnum(prope);
updateCodegenPropertyEnum(prope);
Assert.assertEquals(prope.datatypeWithEnum, "Array<ArrayEnumEnum>");
Assert.assertEquals(prope.enumName, "ArrayEnumEnum");
Assert.assertTrue(prope.isEnum);
@@ -238,7 +240,7 @@ public class TypeScriptFetchModelTest {
Schema property = (Schema) schema.getProperties().get("enum_integer");
CodegenProperty prope = codegen.fromProperty("enum_integer", property);
codegen.updateCodegenPropertyEnum(prope);
updateCodegenPropertyEnum(prope);
Assert.assertEquals(prope.datatypeWithEnum, "EnumIntegerEnum");
Assert.assertEquals(prope.enumName, "EnumIntegerEnum");
Assert.assertTrue(prope.isEnum);