[java] Support for number enum (#3328)

* [java] Support for number enum

*  [core] add isLong, isNumber, isNumeric, isFloat, isDouble to CodegenModel

* [java-gson] fix Enum TypeAdapter in BigDecimal case.
This commit is contained in:
Jérémie Bresson 2019-07-25 04:32:50 +02:00 committed by William Cheng
parent 3f7725c9e2
commit a0dd7394ac
6 changed files with 195 additions and 10 deletions

View File

@ -46,7 +46,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 boolean isString, isInteger, isLong, isNumber, isNumeric, isFloat, isDouble;
public List<CodegenProperty> vars = new ArrayList<CodegenProperty>(); // all properties (without parent's properties)
public List<CodegenProperty> allVars = new ArrayList<CodegenProperty>(); // all properties (with parent's properties)
public List<CodegenProperty> requiredVars = new ArrayList<CodegenProperty>(); // a list of required properties
@ -96,7 +96,12 @@ public class CodegenModel {
.append("arrayModelType", arrayModelType)
.append("isAlias", isAlias)
.append("isString", isString)
.append("isNumeric", isNumeric)
.append("isInteger", isInteger)
.append("isLong", isLong)
.append("isNumber", isNumber)
.append("isFloat", isFloat)
.append("isDouble", isDouble)
.append("vars", vars)
.append("requiredVars", requiredVars)
.append("optionalVars", optionalVars)

View File

@ -1885,14 +1885,27 @@ public class DefaultCodegen implements CodegenConfig {
addAdditionPropertiesToCodeGenModel(m, schema);
m.isMapModel = true;
}
if (ModelUtils.isIntegerSchema(schema)) { // integer type
if (!ModelUtils.isLongSchema(schema)) { // long type is not integer
else if (ModelUtils.isIntegerSchema(schema)) { // integer type
m.isNumeric = Boolean.TRUE;
if (ModelUtils.isLongSchema(schema)) { // int64/long format
m.isLong = Boolean.TRUE;
} else { // int32 format
m.isInteger = Boolean.TRUE;
}
}
if (ModelUtils.isStringSchema(schema)) {
else if (ModelUtils.isStringSchema(schema)) {
m.isString = Boolean.TRUE;
}
else if (ModelUtils.isNumberSchema(schema)) {
m.isNumeric = Boolean.TRUE;
if (ModelUtils.isFloatSchema(schema)) { // float
m.isFloat = Boolean.TRUE;
} else if (ModelUtils.isDoubleSchema(schema)) { // double
m.isDouble = Boolean.TRUE;
} else { // type is number and without format
m.isNumber = Boolean.TRUE;
}
}
// passing null to allProperties and allRequired as there's no parent
addVars(m, unaliasPropertySchema(schema.getProperties()), schema.getRequired(), null, null);
@ -2059,7 +2072,7 @@ public class DefaultCodegen implements CodegenConfig {
String type = getSchemaType(p);
if (ModelUtils.isIntegerSchema(p)) { // integer type
property.isNumeric = Boolean.TRUE;
if (SchemaTypeUtil.INTEGER64_FORMAT.equals(p.getFormat())) { // int64/long format
if (ModelUtils.isLongSchema(p)) { // int64/long format
property.isLong = Boolean.TRUE;
} else { // int32 format
property.isInteger = Boolean.TRUE;

View File

@ -417,6 +417,7 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
// imports for pojos
importMapping.put("ApiModelProperty", "io.swagger.annotations.ApiModelProperty");
importMapping.put("ApiModel", "io.swagger.annotations.ApiModel");
importMapping.put("BigDecimal", "java.math.BigDecimal");
importMapping.put("JsonProperty", "com.fasterxml.jackson.annotation.JsonProperty");
importMapping.put("JsonSubTypes", "com.fasterxml.jackson.annotation.JsonSubTypes");
importMapping.put("JsonTypeInfo", "com.fasterxml.jackson.annotation.JsonTypeInfo");
@ -944,6 +945,9 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
final CodegenModel parentCodegenModel = super.fromModel(codegenModel.parent, parentModel);
codegenModel = AbstractJavaCodegen.reconcileInlineEnums(codegenModel, parentCodegenModel);
}
if ("BigDecimal".equals(codegenModel.dataType)) {
codegenModel.imports.add("BigDecimal");
}
return codegenModel;
}
@ -1107,7 +1111,7 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
// number
if ("Integer".equals(datatype) || "Long".equals(datatype) ||
"Float".equals(datatype) || "Double".equals(datatype)) {
"Float".equals(datatype) || "Double".equals(datatype) || "BigDecimal".equals(datatype)) {
String varName = "NUMBER_" + value;
varName = varName.replaceAll("-", "MINUS_");
varName = varName.replaceAll("\\+", "PLUS_");
@ -1134,6 +1138,9 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
} else if ("Float".equals(datatype)) {
// add f to number, e.g. 3.14 => 3.14f
return value + "f";
} else if ("BigDecimal".equals(datatype)) {
// use BigDecimal String constructor
return "new BigDecimal(\"" + value + "\")";
} else {
return "\"" + escapeText(value) + "\"";
}

View File

@ -65,8 +65,8 @@ public enum {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum
@Override
public {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} read(final JsonReader jsonReader) throws IOException {
{{{dataType}}} value = jsonReader.{{#isInteger}}nextInt(){{/isInteger}}{{^isInteger}}next{{{dataType}}}(){{/isInteger}};
return {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}.fromValue(value);
{{^isNumber}}{{{dataType}}}{{/isNumber}}{{#isNumber}}String{{/isNumber}} value = jsonReader.{{#isNumber}}nextString(){{/isNumber}}{{#isInteger}}nextInt(){{/isInteger}}{{^isNumber}}{{^isInteger}}next{{{dataType}}}(){{/isInteger}}{{/isNumber}};
return {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}.fromValue({{#isNumber}}new BigDecimal({{/isNumber}}value{{#isNumber}}){{/isNumber}});
}
}
{{/gson}}

View File

@ -56,8 +56,8 @@
@Override
public {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}} read(final JsonReader jsonReader) throws IOException {
{{{dataType}}} value = jsonReader.{{#isInteger}}nextInt(){{/isInteger}}{{^isInteger}}next{{{dataType}}}(){{/isInteger}};
return {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}}.fromValue(value);
{{^isNumber}}{{{dataType}}}{{/isNumber}}{{#isNumber}}String{{/isNumber}} value = jsonReader.{{#isNumber}}nextString(){{/isNumber}}{{#isInteger}}nextInt(){{/isInteger}}{{^isNumber}}{{^isInteger}}next{{{dataType}}}(){{/isInteger}}{{/isNumber}};
return {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}}.fromValue({{#isNumber}}new BigDecimal({{/isNumber}}value{{#isNumber}}){{/isNumber}});
}
}
{{/gson}}

View File

@ -578,6 +578,166 @@ public class DefaultCodegenTest {
Assert.assertTrue(property.isNullable);
}
@Test
public void integerSchemaPropertyAndModelTest() {
OpenAPI openAPI = TestUtils.createOpenAPI();
final Schema schema = new IntegerSchema().format("int32");
final DefaultCodegen codegen = new DefaultCodegen();
codegen.setOpenAPI(openAPI);
//Property:
final CodegenProperty cp = codegen.fromProperty("someProperty", schema);
Assert.assertEquals(cp.baseType, "integer");
Assert.assertEquals(cp.baseName, "someProperty");
Assert.assertFalse(cp.isString);
Assert.assertTrue(cp.isInteger);
Assert.assertFalse(cp.isLong);
Assert.assertFalse(cp.isNumber);
Assert.assertTrue(cp.isNumeric);
Assert.assertFalse(cp.isFloat);
Assert.assertFalse(cp.isDouble);
//Model:
final CodegenModel cm = codegen.fromModel("someModel", schema);
Assert.assertEquals(cm.dataType, "integer");
Assert.assertEquals(cm.name, "someModel");
Assert.assertFalse(cm.isString);
Assert.assertTrue(cm.isInteger);
Assert.assertFalse(cm.isLong);
Assert.assertFalse(cm.isNumber);
Assert.assertTrue(cm.isNumeric);
Assert.assertFalse(cm.isFloat);
Assert.assertFalse(cm.isDouble);
}
@Test
public void longSchemaPropertyAndModelTest() {
OpenAPI openAPI = TestUtils.createOpenAPI();
final Schema schema = new IntegerSchema().format("int64");
final DefaultCodegen codegen = new DefaultCodegen();
codegen.setOpenAPI(openAPI);
//Property:
final CodegenProperty cp = codegen.fromProperty("someProperty", schema);
Assert.assertEquals(cp.baseType, "long");
Assert.assertEquals(cp.baseName, "someProperty");
Assert.assertFalse(cp.isString);
Assert.assertFalse(cp.isInteger);
Assert.assertTrue(cp.isLong);
Assert.assertFalse(cp.isNumber);
Assert.assertTrue(cp.isNumeric);
Assert.assertFalse(cp.isFloat);
Assert.assertFalse(cp.isDouble);
//Model:
final CodegenModel cm = codegen.fromModel("someModel", schema);
Assert.assertEquals(cm.dataType, "long");
Assert.assertEquals(cm.name, "someModel");
Assert.assertFalse(cm.isString);
Assert.assertFalse(cm.isInteger);
Assert.assertTrue(cm.isLong);
Assert.assertFalse(cm.isNumber);
Assert.assertTrue(cm.isNumeric);
Assert.assertFalse(cm.isFloat);
Assert.assertFalse(cm.isDouble);
}
@Test
public void numberSchemaPropertyAndModelTest() {
OpenAPI openAPI = TestUtils.createOpenAPI();
final Schema schema = new NumberSchema();
final DefaultCodegen codegen = new DefaultCodegen();
codegen.setOpenAPI(openAPI);
//Property:
final CodegenProperty cp = codegen.fromProperty("someProperty", schema);
Assert.assertEquals(cp.baseType, "number");
Assert.assertEquals(cp.baseName, "someProperty");
Assert.assertFalse(cp.isString);
Assert.assertFalse(cp.isInteger);
Assert.assertFalse(cp.isLong);
Assert.assertTrue(cp.isNumber);
Assert.assertTrue(cp.isNumeric);
Assert.assertFalse(cp.isFloat);
Assert.assertFalse(cp.isDouble);
//Model:
final CodegenModel cm = codegen.fromModel("someModel", schema);
Assert.assertEquals(cm.dataType, "number");
Assert.assertEquals(cm.name, "someModel");
Assert.assertFalse(cm.isString);
Assert.assertFalse(cm.isInteger);
Assert.assertFalse(cm.isLong);
Assert.assertTrue(cm.isNumber);
Assert.assertTrue(cm.isNumeric);
Assert.assertFalse(cm.isFloat);
Assert.assertFalse(cm.isDouble);
}
@Test
public void numberFloatSchemaPropertyAndModelTest() {
OpenAPI openAPI = TestUtils.createOpenAPI();
final Schema schema = new NumberSchema().format("float");
final DefaultCodegen codegen = new DefaultCodegen();
codegen.setOpenAPI(openAPI);
//Property:
final CodegenProperty cp = codegen.fromProperty("someProperty", schema);
Assert.assertEquals(cp.baseType, "float");
Assert.assertEquals(cp.baseName, "someProperty");
Assert.assertFalse(cp.isString);
Assert.assertFalse(cp.isInteger);
Assert.assertFalse(cp.isLong);
Assert.assertFalse(cp.isNumber);
Assert.assertTrue(cp.isNumeric);
Assert.assertTrue(cp.isFloat);
Assert.assertFalse(cp.isDouble);
//Model:
final CodegenModel cm = codegen.fromModel("someModel", schema);
Assert.assertEquals(cm.dataType, "float");
Assert.assertEquals(cm.name, "someModel");
Assert.assertFalse(cm.isString);
Assert.assertFalse(cm.isInteger);
Assert.assertFalse(cm.isLong);
Assert.assertFalse(cm.isNumber);
Assert.assertTrue(cm.isNumeric);
Assert.assertTrue(cm.isFloat);
Assert.assertFalse(cm.isDouble);
}
@Test
public void numberDoubleSchemaPropertyAndModelTest() {
OpenAPI openAPI = TestUtils.createOpenAPI();
final Schema schema = new NumberSchema().format("double");
final DefaultCodegen codegen = new DefaultCodegen();
codegen.setOpenAPI(openAPI);
//Property:
final CodegenProperty cp = codegen.fromProperty("someProperty", schema);
Assert.assertEquals(cp.baseType, "double");
Assert.assertEquals(cp.baseName, "someProperty");
Assert.assertFalse(cp.isString);
Assert.assertFalse(cp.isInteger);
Assert.assertFalse(cp.isLong);
Assert.assertFalse(cp.isNumber);
Assert.assertTrue(cp.isNumeric);
Assert.assertFalse(cp.isFloat);
Assert.assertTrue(cp.isDouble);
//Model:
final CodegenModel cm = codegen.fromModel("someModel", schema);
Assert.assertEquals(cm.dataType, "double");
Assert.assertEquals(cm.name, "someModel");
Assert.assertFalse(cm.isString);
Assert.assertFalse(cm.isInteger);
Assert.assertFalse(cm.isLong);
Assert.assertFalse(cm.isNumber);
Assert.assertTrue(cm.isNumeric);
Assert.assertFalse(cm.isFloat);
Assert.assertTrue(cm.isDouble);
}
private void verifyPersonDiscriminator(CodegenDiscriminator discriminator) {
CodegenDiscriminator test = new CodegenDiscriminator();
test.setPropertyName("DollarUnderscoretype");