mirror of
https://github.com/OpenAPITools/openapi-generator.git
synced 2025-07-05 15:10:49 +00:00
* Fix Issue #21051 * Renamed Test to avoid being overriden by JUnit import * Test fix
This commit is contained in:
parent
c4dad53455
commit
c6a88eaf8e
@ -18,7 +18,9 @@
|
||||
package org.openapitools.codegen.languages;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.samskivert.mustache.Mustache;
|
||||
@ -1399,7 +1401,74 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code
|
||||
return null;
|
||||
} else if (ModelUtils.isObjectSchema(schema)) {
|
||||
if (schema.getDefault() != null) {
|
||||
return super.toDefaultValue(schema);
|
||||
try {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
stringBuilder.append("new " + cp.datatypeWithEnum + "()");
|
||||
Map<String, Schema> propertySchemas = schema.getProperties();
|
||||
if(propertySchemas != null) {
|
||||
// With `parseOptions.setResolve(true)`, objects with 1 key-value pair are LinkedHashMap and objects with more than 1 are ObjectNode
|
||||
// When not set, objects of any size are ObjectNode
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
ObjectNode objectNode;
|
||||
if(!(schema.getDefault() instanceof ObjectNode)) {
|
||||
objectNode = objectMapper.valueToTree(schema.getDefault());
|
||||
} else {
|
||||
objectNode = (ObjectNode) schema.getDefault();
|
||||
|
||||
}
|
||||
Set<Map.Entry<String, JsonNode>> defaultProperties = objectNode.properties();
|
||||
for (Map.Entry<String, JsonNode> defaultProperty : defaultProperties) {
|
||||
String key = defaultProperty.getKey();
|
||||
JsonNode value = defaultProperty.getValue();
|
||||
Schema propertySchema = propertySchemas.get(key);
|
||||
if (!value.isValueNode() || propertySchema == null) { //Skip complex objects for now
|
||||
continue;
|
||||
}
|
||||
|
||||
String defaultPropertyExpression = null;
|
||||
if(ModelUtils.isLongSchema(propertySchema)) {
|
||||
defaultPropertyExpression = value.asText()+"l";
|
||||
} else if(ModelUtils.isIntegerSchema(propertySchema)) {
|
||||
defaultPropertyExpression = value.asText();
|
||||
} else if(ModelUtils.isDoubleSchema(propertySchema)) {
|
||||
defaultPropertyExpression = value.asText()+"d";
|
||||
} else if(ModelUtils.isFloatSchema(propertySchema)) {
|
||||
defaultPropertyExpression = value.asText()+"f";
|
||||
} else if(ModelUtils.isNumberSchema(propertySchema)) {
|
||||
defaultPropertyExpression = "new java.math.BigDecimal(\"" + value.asText() + "\")";
|
||||
} else if(ModelUtils.isURISchema(propertySchema)) {
|
||||
defaultPropertyExpression = "java.net.URI.create(\"" + escapeText(value.asText()) + "\")";
|
||||
} else if(ModelUtils.isDateSchema(propertySchema)) {
|
||||
if("java8".equals(getDateLibrary())) {
|
||||
defaultPropertyExpression = String.format(Locale.ROOT, "java.time.LocalDate.parse(\"%s\")", value.asText());
|
||||
}
|
||||
} else if(ModelUtils.isDateTimeSchema(propertySchema)) {
|
||||
if("java8".equals(getDateLibrary())) {
|
||||
defaultPropertyExpression = String.format(Locale.ROOT, "java.time.OffsetDateTime.parse(\"%s\", %s)",
|
||||
value.asText(),
|
||||
"java.time.format.DateTimeFormatter.ISO_ZONED_DATE_TIME.withZone(java.time.ZoneId.systemDefault())");
|
||||
}
|
||||
} else if(ModelUtils.isUUIDSchema(propertySchema)) {
|
||||
defaultPropertyExpression = "java.util.UUID.fromString(\"" + value.asText() + "\")";
|
||||
} else if(ModelUtils.isStringSchema(propertySchema)) {
|
||||
defaultPropertyExpression = "\"" + value.asText() + "\"";
|
||||
} else if(ModelUtils.isBooleanSchema(propertySchema)) {
|
||||
defaultPropertyExpression = value.asText();
|
||||
}
|
||||
if(defaultPropertyExpression != null) {
|
||||
stringBuilder
|
||||
// .append(System.lineSeparator())
|
||||
.append(".")
|
||||
.append(toVarName(key))
|
||||
.append("(").append(defaultPropertyExpression).append(")");
|
||||
}
|
||||
}
|
||||
}
|
||||
return stringBuilder.toString();
|
||||
} catch (ClassCastException e) {
|
||||
LOGGER.error("Can't resolve default value: "+schema.getDefault(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} else if (ModelUtils.isComposedSchema(schema)) {
|
||||
|
@ -17,6 +17,12 @@
|
||||
|
||||
package org.openapitools.codegen.java;
|
||||
|
||||
import com.github.javaparser.StaticJavaParser;
|
||||
import com.github.javaparser.ast.CompilationUnit;
|
||||
import com.github.javaparser.ast.body.FieldDeclaration;
|
||||
import com.github.javaparser.ast.expr.Expression;
|
||||
import com.github.javaparser.ast.expr.MethodCallExpr;
|
||||
import com.github.javaparser.ast.visitor.*;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import io.swagger.parser.OpenAPIParser;
|
||||
import io.swagger.v3.oas.models.OpenAPI;
|
||||
@ -60,7 +66,7 @@ import java.util.stream.Collectors;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.entry;
|
||||
import static org.assertj.core.api.InstanceOfAssertFactories.FILE;
|
||||
import static org.openapitools.codegen.CodegenConstants.SERIALIZATION_LIBRARY;
|
||||
import static org.openapitools.codegen.CodegenConstants.*;
|
||||
import static org.openapitools.codegen.TestUtils.newTempFolder;
|
||||
import static org.openapitools.codegen.TestUtils.validateJavaSourceFiles;
|
||||
import static org.openapitools.codegen.languages.JavaClientCodegen.*;
|
||||
@ -3592,4 +3598,71 @@ public class JavaClientCodegenTest {
|
||||
"public some.pkg.B getsomepkgB() throws ClassCastException {"
|
||||
);
|
||||
}
|
||||
|
||||
@Test(description = "Issue #21051")
|
||||
public void givenComplexObjectHasDefaultValueWhenGenerateThenDefaultAssignmentsAreValid() throws Exception {
|
||||
File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
|
||||
output.deleteOnExit();
|
||||
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put(APIS, false);
|
||||
properties.put(API_DOCS, false);
|
||||
properties.put(API_TESTS, false);
|
||||
properties.put(MODEL_DOCS, false);
|
||||
properties.put(MODEL_TESTS, false);
|
||||
|
||||
Generator generator = new DefaultGenerator();
|
||||
CodegenConfigurator configurator = new CodegenConfigurator()
|
||||
.setInputSpec("src/test/resources/3_1/issue_21051.yaml")
|
||||
.setGeneratorName("java")
|
||||
.setAdditionalProperties(properties)
|
||||
.setOutputDir(output.getAbsolutePath());
|
||||
ClientOptInput clientOptInput = configurator.toClientOptInput();
|
||||
generator.opts(clientOptInput)
|
||||
.generate();
|
||||
System.out.println("Generator Settings: " + clientOptInput.getGeneratorSettings());
|
||||
String outputPath = output.getAbsolutePath() + "/src/main/java/org/openapitools";
|
||||
File testModel = new File(outputPath, "/client/model/TestCase.java");
|
||||
String fileContent = Files.readString(testModel.toPath());
|
||||
|
||||
System.out.println(fileContent);
|
||||
TestUtils.assertValidJavaSourceCode(fileContent);
|
||||
CompilationUnit compilationUnit = StaticJavaParser.parse(testModel);
|
||||
Map<String, FieldDeclaration> defaultFields = compilationUnit.getType(0).getFields().stream()
|
||||
.collect(Collectors.toMap((f) -> f.getVariable(0).getName().asString(), (f) -> f));
|
||||
//chain method calls for object initialization
|
||||
class MethodCallVisitor extends VoidVisitorAdapter<Void> {
|
||||
Map<String, Expression> expressionMap = new HashMap<>();
|
||||
@Override
|
||||
public void visit(MethodCallExpr n, Void arg) {
|
||||
expressionMap.put(n.getNameAsString(), n.getArgument(0));
|
||||
if(n.getScope().isPresent()) {
|
||||
n.getScope().get().accept(this, arg);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
MethodCallVisitor visitor = new MethodCallVisitor();
|
||||
defaultFields.get("testComplexInlineObject").getVariable(0).getInitializer().get().asMethodCallExpr()
|
||||
.accept(visitor, null);
|
||||
Map<String, Expression> expressionMap = visitor.expressionMap;
|
||||
assertTrue(expressionMap.get("foo").isStringLiteralExpr());
|
||||
assertTrue(expressionMap.get("fooInt").isIntegerLiteralExpr());
|
||||
assertTrue(expressionMap.get("fooLong").isLongLiteralExpr());
|
||||
assertTrue(expressionMap.get("fooBool").isBooleanLiteralExpr());
|
||||
assertTrue(expressionMap.get("fooFloat").isDoubleLiteralExpr());
|
||||
assertTrue(expressionMap.get("fooDouble").isDoubleLiteralExpr());
|
||||
assertTrue(expressionMap.containsKey("_void"));
|
||||
|
||||
assertFalse(expressionMap.containsKey("nonExistentDefault"));
|
||||
assertFalse(expressionMap.containsKey("nonDefaultedProperty"));
|
||||
|
||||
assertTrue(defaultFields.get("testEmptyInlineObject").getVariable(0).getInitializer().get().isObjectCreationExpr());
|
||||
assertTrue(defaultFields.get("testNullableEmptyInlineObject").getVariable(0).getInitializer().get().isObjectCreationExpr());
|
||||
assertTrue(defaultFields.get("testNullableComplexInlineObject").getVariable(0).getInitializer().get().isMethodCallExpr());
|
||||
assertTrue(defaultFields.get("testEmptyReference").getVariable(0).getInitializer().get().isObjectCreationExpr());
|
||||
assertTrue(defaultFields.get("testComplexReference").getVariable(0).getInitializer().get().isMethodCallExpr());
|
||||
assertTrue(defaultFields.get("testNullableEmptyReference").getVariable(0).getInitializer().get().isObjectCreationExpr());
|
||||
assertTrue(defaultFields.get("testNullableComplexReference").getVariable(0).getInitializer().get().isMethodCallExpr());
|
||||
}
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
# Modified from the original
|
||||
openapi: 3.1.0
|
||||
info:
|
||||
title: Petstore API
|
||||
description: Petstore API
|
||||
version: 1.0.0
|
||||
servers:
|
||||
- url: 'http://localhost'
|
||||
components:
|
||||
schemas:
|
||||
# Not generated - free-form object
|
||||
EmptyReferenceObject:
|
||||
type: object
|
||||
default: {}
|
||||
ComplexReferenceObject:
|
||||
type: object
|
||||
default:
|
||||
foo: bar
|
||||
properties:
|
||||
foo:
|
||||
type: string
|
||||
nullable: true
|
||||
NullableEmptyReferenceObject:
|
||||
type: object
|
||||
default: {}
|
||||
nullable: true
|
||||
NullableComplexReferenceObject:
|
||||
type: object
|
||||
default:
|
||||
foo: bar
|
||||
properties:
|
||||
foo:
|
||||
type: string
|
||||
nullable: true
|
||||
nullable: true
|
||||
TestCase:
|
||||
type: object
|
||||
properties:
|
||||
testEmptyInlineObject:
|
||||
type: object
|
||||
default: {}
|
||||
testComplexInlineObject:
|
||||
type: object
|
||||
default:
|
||||
foo: bar
|
||||
fooInt: 28
|
||||
fooLong: 5000000000
|
||||
fooBool: true
|
||||
fooFloat: 32.5
|
||||
fooDouble: 3332.555
|
||||
fooNumber: 120.6
|
||||
fooDateTime: "2000-01-01T20:20:20+00:00"
|
||||
fooUUID: "a0ed70ec-5fe5-415a-be97-a7bf13db9fb6"
|
||||
void: empty
|
||||
nonExistentDefault: 27
|
||||
properties:
|
||||
foo:
|
||||
type: string
|
||||
nullable: true
|
||||
fooInt:
|
||||
type: integer
|
||||
nullable: true
|
||||
fooLong:
|
||||
type: integer
|
||||
format: int64
|
||||
nullable: true
|
||||
fooBool:
|
||||
type: boolean
|
||||
fooFloat:
|
||||
type: number
|
||||
format: float
|
||||
nullable: true
|
||||
fooDouble:
|
||||
type: number
|
||||
format: double
|
||||
nullable: true
|
||||
fooNumber:
|
||||
type: number
|
||||
nullable: true
|
||||
fooDateTime:
|
||||
type: string
|
||||
format: date-time
|
||||
nullable: true
|
||||
fooUUID:
|
||||
type: string
|
||||
format: uuid
|
||||
nullable: true
|
||||
void: # Java keyword
|
||||
type: string
|
||||
nullable: true
|
||||
nonDefaultedProperty:
|
||||
type: string
|
||||
nullable: true
|
||||
testNullableEmptyInlineObject:
|
||||
type: object
|
||||
default: {}
|
||||
nullable: true
|
||||
testNullableComplexInlineObject:
|
||||
type: object
|
||||
default:
|
||||
foo: bar
|
||||
properties:
|
||||
foo:
|
||||
type: string
|
||||
nullable: true
|
||||
nullable: true
|
||||
testEmptyReference:
|
||||
$ref: '#/components/schemas/EmptyReferenceObject'
|
||||
testComplexReference:
|
||||
$ref: '#/components/schemas/ComplexReferenceObject'
|
||||
testNullableEmptyReference:
|
||||
$ref: '#/components/schemas/NullableEmptyReferenceObject'
|
||||
testNullableComplexReference:
|
||||
$ref: '#/components/schemas/NullableComplexReferenceObject'
|
Loading…
x
Reference in New Issue
Block a user