[Java, kotlin] Manage List<Integer> datatype for enum (#75)

This commit is contained in:
Thibault Duperron 2018-06-27 05:51:35 +02:00 committed by Jérémie Bresson
parent ea81b0c833
commit b6717a5bad
11 changed files with 171 additions and 42 deletions

View File

@ -44,6 +44,7 @@ public class CodegenModel {
public String defaultValue;
public String arrayModelType;
public boolean isAlias; // Is this effectively an alias of another simple type
public boolean isString, isInteger;
public List<CodegenProperty> vars = new ArrayList<CodegenProperty>();
public List<CodegenProperty> requiredVars = new ArrayList<CodegenProperty>(); // a list of required properties
public List<CodegenProperty> optionalVars = new ArrayList<CodegenProperty>(); // a list of optional properties

View File

@ -250,11 +250,11 @@ public class DefaultCodegen implements CodegenConfig {
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>>();
List<Map<String, Object>> enumVars = new ArrayList<Map<String, Object>>();
String commonPrefix = findCommonPrefixOfVars(values);
int truncateIdx = commonPrefix.length();
for (Object value : values) {
Map<String, String> enumVar = new HashMap<String, String>();
Map<String, Object> enumVar = new HashMap<String, Object>();
String enumName;
if (truncateIdx == 0) {
enumName = value.toString();
@ -266,6 +266,7 @@ public class DefaultCodegen implements CodegenConfig {
}
enumVar.put("name", toEnumVarName(enumName, cm.dataType));
enumVar.put("value", toEnumValue(value.toString(), cm.dataType));
enumVar.put("isString", isDataTypeString(cm.dataType));
enumVars.add(enumVar);
}
cm.allowableValues.put("enumVars", enumVars);
@ -1524,6 +1525,15 @@ public class DefaultCodegen implements CodegenConfig {
if (ModelUtils.isMapSchema(schema)) {
addAdditionPropertiesToCodeGenModel(m, schema);
}
if (ModelUtils.isIntegerSchema(schema)) { // integer type
if (!ModelUtils.isLongSchema(schema)) { // long type is not integer
m.isInteger = Boolean.TRUE;
}
}
if (ModelUtils.isStringSchema(schema)){
m.isString = Boolean.TRUE;
}
addVars(m, unaliasPropertySchema(allDefinitions, schema.getProperties()), schema.getRequired());
}
@ -3678,11 +3688,11 @@ public class DefaultCodegen implements CodegenConfig {
}
// put "enumVars" map into `allowableValues", including `name` and `value`
List<Map<String, String>> enumVars = new ArrayList<Map<String, String>>();
List<Map<String, Object>> enumVars = new ArrayList<>();
String commonPrefix = findCommonPrefixOfVars(values);
int truncateIdx = commonPrefix.length();
for (Object value : values) {
Map<String, String> enumVar = new HashMap<String, String>();
Map<String, Object> enumVar = new HashMap<>();
String enumName;
if (truncateIdx == 0) {
enumName = value.toString();
@ -3692,8 +3702,11 @@ public class DefaultCodegen implements CodegenConfig {
enumName = value.toString();
}
}
enumVar.put("name", toEnumVarName(enumName, var.dataType));
enumVar.put("value", toEnumValue(value.toString(), var.dataType));
final String dataType = var.mostInnerItems != null ? var.mostInnerItems.dataType : var.dataType;
enumVar.put("name", toEnumVarName(enumName, dataType));
enumVar.put("value", toEnumValue(value.toString(), dataType));
enumVar.put("isString", isDataTypeString(dataType));
enumVars.add(enumVar);
}
allowableValues.put("enumVars", enumVars);
@ -3701,9 +3714,9 @@ public class DefaultCodegen implements CodegenConfig {
// handle default value for enum, e.g. available => StatusEnum.AVAILABLE
if (var.defaultValue != null) {
String enumName = null;
for (Map<String, String> enumVar : enumVars) {
for (Map<String, Object> enumVar : enumVars) {
if (toEnumValue(var.defaultValue, var.dataType).equals(enumVar.get("value"))) {
enumName = enumVar.get("name");
enumName = (String) enumVar.get("name");
break;
}
}
@ -4362,4 +4375,7 @@ public class DefaultCodegen implements CodegenConfig {
}
}
public boolean isDataTypeString(String dataType) {
return "String".equals(dataType);
}
}

View File

@ -557,4 +557,26 @@ public abstract class AbstractKotlinCodegen extends DefaultCodegen implements Co
boolean imports = !type.startsWith("kotlin.") && !type.startsWith("java.") && !defaultIncludes.contains(type) && !languageSpecificPrimitives.contains(type);
return imports;
}
@Override
public String toEnumValue(String value, String datatype) {
if ("kotlin.Int".equals(datatype) || "kotlin.Long".equals(datatype)) {
return value;
} else if ("kotlin.Double".equals(datatype)) {
if (value.contains(".")) {
return value;
} else {
return value + ".0"; // Float and double must have .0
}
} else if ("kotlin.Float".equals(datatype)) {
return value + "f";
} else {
return "\"" + escapeText(value) + "\"";
}
}
@Override
public boolean isDataTypeString(final String dataType) {
return "String".equals(dataType) || "kotlin.String".equals(dataType);
}
}

View File

@ -3,7 +3,7 @@
public enum {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} {
{{#allowableValues}}
{{#enumVars}}@XmlEnumValue({{{value}}}) {{name}}({{dataType}}.valueOf({{{value}}})){{^-last}}, {{/-last}}{{#-last}};{{/-last}}{{/enumVars}}
{{#enumVars}}@XmlEnumValue({{^isString}}"{{/isString}}{{{value}}}{{^isString}}"{{/isString}}) {{name}}({{dataType}}.valueOf({{{value}}})){{^-last}}, {{/-last}}{{#-last}};{{/-last}}{{/enumVars}}
{{/allowableValues}}
@ -13,7 +13,7 @@ public enum {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum
value = v;
}
public String value() {
public {{dataType}} value() {
return value;
}

View File

@ -6,6 +6,6 @@ import com.squareup.moshi.Json
*/
enum class {{classname}}(val value: {{dataType}}){
{{#allowableValues}}{{#enumVars}}
@Json(name = {{{value}}}) {{&name}}({{{value}}}){{^-last}},{{/-last}}{{#-last}};{{/-last}}
@Json(name = {{^isString}}"{{/isString}}{{{value}}}{{^isString}}"{{/isString}}) {{&name}}({{{value}}}){{^-last}},{{/-last}}{{#-last}};{{/-last}}
{{/enumVars}}{{/allowableValues}}
}

View File

@ -33,8 +33,10 @@ import org.testng.Assert;
import org.testng.annotations.Test;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -202,7 +204,7 @@ public class DefaultCodegenTest {
Assert.assertEquals(co.produces.size(), 1);
Assert.assertEquals(co.produces.get(0).get("mediaType"), "application/json");
}
@Test
public void testGetSchemaTypeWithComposedSchemaWithOneOf() {
final OpenAPI openAPI = new OpenAPIParser().readLocation("src/test/resources/3_0/composed-oneof.yaml", null, new ParseOptions()).getOpenAPI();
@ -214,4 +216,32 @@ public class DefaultCodegenTest {
Assert.assertNotNull(type);
}
@Test
public void updateCodegenPropertyEnum() {
final DefaultCodegen codegen = new DefaultCodegen();
CodegenProperty array = codegenPropertyWithArrayOfIntegerValues();
codegen.updateCodegenPropertyEnum(array);
List<Map<String, Object>> enumVars = (List<Map<String, Object>>) array.getItems().getAllowableValues().get("enumVars");
Assert.assertNotNull(enumVars);
Map<String, Object> testedEnumVar = enumVars.get(0);
Assert.assertNotNull(testedEnumVar);
Assert.assertEquals(testedEnumVar.getOrDefault("name", ""),"_1");
Assert.assertEquals(testedEnumVar.getOrDefault("value", ""), "\"1\"");
Assert.assertEquals(testedEnumVar.getOrDefault("isString", ""), false);
}
private CodegenProperty codegenPropertyWithArrayOfIntegerValues() {
CodegenProperty array = new CodegenProperty();
final CodegenProperty items = new CodegenProperty();
final HashMap<String, Object> allowableValues = new HashMap<>();
allowableValues.put("values", Collections.singletonList(1));
items.setAllowableValues(allowableValues);
items.dataType = "Integer";
array.setItems(items);
array.dataType = "Array";
return array;
}
}

View File

@ -136,6 +136,15 @@ public class AbstractJavaCodegenTest {
Assert.assertEquals(codegen.additionalProperties().get(CodegenConstants.INVOKER_PACKAGE), "xyz.yyyyy.invoker.oooooo");
}
@Test
public void toEnumValue(){
final AbstractJavaCodegen codegen = new P_AbstractJavaCodegen();
Assert.assertEquals(codegen.toEnumValue("1", "Integer"), "1");
Assert.assertEquals(codegen.toEnumValue("42", "Double"), "42");
Assert.assertEquals(codegen.toEnumValue("1337", "Long"), "1337l");
Assert.assertEquals(codegen.toEnumValue("3.14", "Float"), "3.14f");
}
private static class P_AbstractJavaCodegen extends AbstractJavaCodegen {
@Override
public CodegenType getTag() {

View File

@ -34,12 +34,7 @@ import io.swagger.v3.oas.models.parameters.RequestBody;
import io.swagger.v3.parser.core.models.ParseOptions;
import io.swagger.v3.parser.util.SchemaTypeUtil;
import org.openapitools.codegen.CodegenConstants;
import org.openapitools.codegen.CodegenModel;
import org.openapitools.codegen.CodegenModelFactory;
import org.openapitools.codegen.CodegenModelType;
import org.openapitools.codegen.CodegenOperation;
import org.openapitools.codegen.CodegenParameter;
import org.openapitools.codegen.*;
import org.openapitools.codegen.languages.JavaClientCodegen;
import org.openapitools.codegen.utils.ModelUtils;
import org.testng.Assert;
@ -309,7 +304,7 @@ public class JavaClientCodegenTest {
Assert.assertEquals(codegen.getInvokerPackage(), "xyz.yyyyy.zzzzzzz.mmmmm");
Assert.assertEquals(codegen.additionalProperties().get(CodegenConstants.INVOKER_PACKAGE), "xyz.yyyyy.zzzzzzz.mmmmm");
}
@Test
public void testGetSchemaTypeWithComposedSchemaWithAllOf() {
final OpenAPI openAPI = new OpenAPIParser().readLocation("src/test/resources/2_0/composed-allof.yaml", null, new ParseOptions()).getOpenAPI();
@ -321,6 +316,34 @@ public class JavaClientCodegenTest {
Assert.assertEquals(co.allParams.get(0).baseType, "MessageEventCoreWithTimeListEntries");
}
@Test
public void updateCodegenPropertyEnum() {
final JavaClientCodegen codegen = new JavaClientCodegen();
CodegenProperty array = codegenPropertyWithArrayOfIntegerValues();
codegen.updateCodegenPropertyEnum(array);
List<Map<String, String>> enumVars = (List<Map<String, String>>) array.getItems().getAllowableValues().get("enumVars");
Assert.assertNotNull(enumVars);
Map<String, String> testedEnumVar = enumVars.get(0);
Assert.assertNotNull(testedEnumVar);
Assert.assertEquals(testedEnumVar.getOrDefault("name", ""),"NUMBER_1");
Assert.assertEquals(testedEnumVar.getOrDefault("value", ""), "1");
}
private CodegenProperty codegenPropertyWithArrayOfIntegerValues() {
CodegenProperty array = new CodegenProperty();
final CodegenProperty items = new CodegenProperty();
final HashMap<String, Object> allowableValues = new HashMap<>();
allowableValues.put("values", Collections.singletonList(1));
items.setAllowableValues(allowableValues);
items.dataType = "Integer";
array.setItems(items);
array.dataType = "Array";
array.mostInnerItems = items;
return array;
}
private CodegenParameter createPathParam(String name) {
CodegenParameter codegenParameter = createStringParam(name);
codegenParameter.isPathParam = true;

View File

@ -6,6 +6,9 @@ import org.testng.Assert;
import org.testng.annotations.Test;
import static org.openapitools.codegen.CodegenConstants.ENUM_PROPERTY_NAMING_TYPE.*;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
public class AbstractKotlinCodegenTest {
@ -14,41 +17,51 @@ public class AbstractKotlinCodegenTest {
@Test
public void camlCaseEnumConverter() {
codegen.setEnumPropertyNaming(camelCase.name());
Assert.assertEquals(codegen.toEnumVarName("long Name", null), "longName");
Assert.assertEquals(codegen.toEnumVarName("1long Name", null), "_1longName");
Assert.assertEquals(codegen.toEnumVarName("not1long Name", null), "not1longName");
assertEquals(codegen.toEnumVarName("long Name", null), "longName");
assertEquals(codegen.toEnumVarName("1long Name", null), "_1longName");
assertEquals(codegen.toEnumVarName("not1long Name", null), "not1longName");
}
@Test
public void uppercasEnumConverter() {
codegen.setEnumPropertyNaming(UPPERCASE.name());
Assert.assertEquals(codegen.toEnumVarName("long Name", null), "LONG_NAME");
Assert.assertEquals(codegen.toEnumVarName("1long Name", null), "_1LONG_NAME");
Assert.assertEquals(codegen.toEnumVarName("not1long Name", null), "NOT1LONG_NAME");
assertEquals(codegen.toEnumVarName("long Name", null), "LONG_NAME");
assertEquals(codegen.toEnumVarName("1long Name", null), "_1LONG_NAME");
assertEquals(codegen.toEnumVarName("not1long Name", null), "NOT1LONG_NAME");
}
@Test
public void snake_caseEnumConverter() {
codegen.setEnumPropertyNaming(snake_case.name());
Assert.assertEquals(codegen.toEnumVarName("long Name", null), "long_name");
Assert.assertEquals(codegen.toEnumVarName("1long Name", null), "_1long_name");
Assert.assertEquals(codegen.toEnumVarName("not1long Name", null), "not1long_name");
assertEquals(codegen.toEnumVarName("long Name", null), "long_name");
assertEquals(codegen.toEnumVarName("1long Name", null), "_1long_name");
assertEquals(codegen.toEnumVarName("not1long Name", null), "not1long_name");
}
@Test
public void originalEnumConverter() {
codegen.setEnumPropertyNaming(original.name());
Assert.assertEquals(codegen.toEnumVarName("long Name", null), "long_Name");
Assert.assertEquals(codegen.toEnumVarName("1long Name", null), "_1long_Name");
Assert.assertEquals(codegen.toEnumVarName("not1long Name", null), "not1long_Name");
assertEquals(codegen.toEnumVarName("long Name", null), "long_Name");
assertEquals(codegen.toEnumVarName("1long Name", null), "_1long_Name");
assertEquals(codegen.toEnumVarName("not1long Name", null), "not1long_Name");
}
@Test
public void pascalCaseEnumConverter() {
codegen.setEnumPropertyNaming(PascalCase.name());
Assert.assertEquals(codegen.toEnumVarName("long Name", null), "LongName");
Assert.assertEquals(codegen.toEnumVarName("1long Name", null), "_1longName");
Assert.assertEquals(codegen.toEnumVarName("not1long Name", null), "Not1longName");
assertEquals(codegen.toEnumVarName("long Name", null), "LongName");
assertEquals(codegen.toEnumVarName("1long Name", null), "_1longName");
assertEquals(codegen.toEnumVarName("not1long Name", null), "Not1longName");
}
@Test
public void toEnumValue(){
assertEquals(codegen.toEnumValue("1", "kotlin.Int"), "1");
assertEquals(codegen.toEnumValue("1", "kotlin.Double"), "1.0");
assertEquals(codegen.toEnumValue("1.3", "kotlin.Double"), "1.3");
assertEquals(codegen.toEnumValue("1337", "kotlin.Long"), "1337");
assertEquals(codegen.toEnumValue("5", "kotlin.Float"), "5f");
assertEquals(codegen.toEnumValue("1.0", "kotlin.Float"), "1.0f");
assertEquals(codegen.toEnumValue("data", "Something"), "\"data\"");
}
private class P_AbstractKotlinCodegen extends AbstractKotlinCodegen {
@Override
@ -66,4 +79,11 @@ public class AbstractKotlinCodegenTest {
return null;
}
}
@Test
public void isDataTypeString(){
assertFalse(codegen.isDataTypeString("kotlin.Int"));
assertTrue(codegen.isDataTypeString("kotlin.String"));
assertTrue(codegen.isDataTypeString("String"));
}
}

View File

@ -310,12 +310,14 @@ public class PhpModelTest {
Assert.assertTrue(prope.isEnum);
Assert.assertEquals(prope.allowableValues.get("values"), Arrays.asList("fish", "crab"));
HashMap<String, String> fish= new HashMap<String, String>();
HashMap<String, Object> fish= new HashMap<String, Object>();
fish.put("name", "FISH");
fish.put("value", "\'fish\'");
HashMap<String, String> crab= new HashMap<String, String>();
fish.put("isString", false);
HashMap<String, Object> crab= new HashMap<String, Object>();
crab.put("name", "CRAB");
crab.put("value", "\'crab\'");
crab.put("isString", false);
Assert.assertEquals(prope.allowableValues.get("enumVars"), Arrays.asList(fish, crab));
// assert inner items
@ -343,12 +345,14 @@ public class PhpModelTest {
Assert.assertNull(prope.items);
Assert.assertEquals(prope.allowableValues.get("values"), Arrays.asList(1, -1));
HashMap<String, String> one = new HashMap<String, String>();
HashMap<String, Object> one = new HashMap<String, Object>();
one.put("name", "1");
one.put("value", "1");
HashMap<String, String> minusOne = new HashMap<String, String>();
one.put("isString", false);
HashMap<String, Object> minusOne = new HashMap<String, Object>();
minusOne.put("name", "MINUS_1");
minusOne.put("value", "-1");
minusOne.put("isString", false);
Assert.assertEquals(prope.allowableValues.get("enumVars"), Arrays.asList(one, minusOne));
}

View File

@ -234,12 +234,14 @@ public class TypeScriptFetchModelTest {
Assert.assertTrue(prope.isEnum);
Assert.assertEquals(prope.allowableValues.get("values"), Arrays.asList("fish", "crab"));
HashMap<String, String> fish = new HashMap<String, String>();
HashMap<String, Object> fish = new HashMap<String, Object>();
fish.put("name", "Fish");
fish.put("value", "'fish'");
HashMap<String, String> crab = new HashMap<String, String>();
fish.put("isString", false);
HashMap<String, Object> crab = new HashMap<String, Object>();
crab.put("name", "Crab");
crab.put("value", "'crab'");
crab.put("isString", false);
Assert.assertEquals(prope.allowableValues.get("enumVars"), Arrays.asList(fish, crab));
// assert inner items
@ -270,12 +272,14 @@ public class TypeScriptFetchModelTest {
Assert.assertNull(prope.items);
Assert.assertEquals(prope.allowableValues.get("values"), Arrays.asList(1, -1));
HashMap<String, String> one = new HashMap<String, String>();
HashMap<String, Object> one = new HashMap<String, Object>();
one.put("name", "NUMBER_1");
one.put("value", "1");
HashMap<String, String> minusOne = new HashMap<String, String>();
one.put("isString", false);
HashMap<String, Object> minusOne = new HashMap<String, Object>();
minusOne.put("name", "NUMBER_MINUS_1");
minusOne.put("value", "-1");
minusOne.put("isString", false);
Assert.assertEquals(prope.allowableValues.get("enumVars"), Arrays.asList(one, minusOne));
//IMPORTANT: these are not final enum values, which may be further updated