forked from loafle/openapi-generator-original
Add new method to detect self-referencing in ModelUtils (#12294)
* fix unaliasing object schema, add tests * add self reference check * add self reference check, add test
This commit is contained in:
parent
b02fd28ba6
commit
d97c152c14
@ -1065,6 +1065,96 @@ public class ModelUtils {
|
||||
return entry.getValue().getSchema();
|
||||
}
|
||||
|
||||
/**
|
||||
* Has self reference?
|
||||
*
|
||||
* @param openAPI OpenAPI spec.
|
||||
* @param schema Schema
|
||||
* @return boolean true if it has at least one self reference
|
||||
*/
|
||||
public static boolean hasSelfReference(OpenAPI openAPI,
|
||||
Schema schema) {
|
||||
return hasSelfReference(openAPI, schema, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Has self reference?
|
||||
*
|
||||
* @param openAPI OpenAPI spec.
|
||||
* @param schema Schema
|
||||
* @param visitedSchemaNames A set of visited schema names
|
||||
* @return boolean true if it has at least one self reference
|
||||
*/
|
||||
public static boolean hasSelfReference(OpenAPI openAPI,
|
||||
Schema schema,
|
||||
Set<String> visitedSchemaNames) {
|
||||
if (visitedSchemaNames == null) {
|
||||
visitedSchemaNames = new HashSet<String>();
|
||||
}
|
||||
|
||||
if (schema.get$ref() != null) {
|
||||
String ref = getSimpleRef(schema.get$ref());
|
||||
if (!visitedSchemaNames.contains(ref)) {
|
||||
visitedSchemaNames.add(ref);
|
||||
Schema referencedSchema = getSchemas(openAPI).get(ref);
|
||||
if (referencedSchema != null) {
|
||||
return hasSelfReference(openAPI, referencedSchema, visitedSchemaNames);
|
||||
} else {
|
||||
LOGGER.error("Failed to obtain schema from `{}` in self reference check", ref);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (schema instanceof ComposedSchema) {
|
||||
List<Schema> oneOf = ((ComposedSchema) schema).getOneOf();
|
||||
if (oneOf != null) {
|
||||
for (Schema s : oneOf) {
|
||||
if (hasSelfReference(openAPI, s, visitedSchemaNames)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
List<Schema> allOf = ((ComposedSchema) schema).getAllOf();
|
||||
if (allOf != null) {
|
||||
for (Schema s : allOf) {
|
||||
if (hasSelfReference(openAPI, s, visitedSchemaNames)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
List<Schema> anyOf = ((ComposedSchema) schema).getAnyOf();
|
||||
if (anyOf != null) {
|
||||
for (Schema s : anyOf) {
|
||||
if (hasSelfReference(openAPI, s, visitedSchemaNames)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (isArraySchema(schema)) {
|
||||
Schema itemsSchema = ((ArraySchema) schema).getItems();
|
||||
if (itemsSchema != null) {
|
||||
return hasSelfReference(openAPI, itemsSchema, visitedSchemaNames);
|
||||
}
|
||||
} else if (isMapSchema(schema)) {
|
||||
Object additionalProperties = schema.getAdditionalProperties();
|
||||
if (additionalProperties instanceof Schema) {
|
||||
return hasSelfReference(openAPI, (Schema) additionalProperties, visitedSchemaNames);
|
||||
}
|
||||
} else if (schema.getNot() != null) {
|
||||
return hasSelfReference(openAPI, schema.getNot(), visitedSchemaNames);
|
||||
} else if (schema.getProperties() != null && !schema.getProperties().isEmpty()) {
|
||||
// go through properties to see if there's any self-reference
|
||||
for (Schema property : ((Map<String, Schema>)schema.getProperties()).values()) {
|
||||
if (hasSelfReference(openAPI, property, visitedSchemaNames)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actual schema from aliases. If the provided schema is not an alias, the schema itself will be returned.
|
||||
*
|
||||
@ -1131,7 +1221,14 @@ public class ModelUtils {
|
||||
}
|
||||
} else if (isObjectSchema(ref)) { // model
|
||||
if (ref.getProperties() != null && !ref.getProperties().isEmpty()) { // has at least one property
|
||||
return schema;
|
||||
if (hasSelfReference(openAPI, ref)) {
|
||||
// it's self referencing so returning itself instead
|
||||
return schema;
|
||||
} else {
|
||||
// TODO we may revise below to return `ref` instead of schema
|
||||
// which is the last reference to the actual model/object
|
||||
return schema;
|
||||
}
|
||||
} else { // free form object (type: object)
|
||||
return unaliasSchema(openAPI, allSchemas.get(ModelUtils.getSimpleRef(schema.get$ref())),
|
||||
importMappings);
|
||||
|
@ -4125,4 +4125,29 @@ public class DefaultCodegenTest {
|
||||
assertEquals(cp.baseName, "SchemaFor201ResponseBodyTextPlain");
|
||||
assertTrue(cp.isString);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnalias() {
|
||||
final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/schema-unalias-test.yml");
|
||||
final DefaultCodegen codegen = new DefaultCodegen();
|
||||
codegen.setOpenAPI(openAPI);
|
||||
|
||||
Schema requestBodySchema = ModelUtils.getSchemaFromRequestBody(
|
||||
openAPI.getPaths().get("/thingy/{date}").getPost().getRequestBody());
|
||||
Assert.assertEquals(requestBodySchema.get$ref(), "#/components/schemas/updatePetWithForm_request");
|
||||
Assert.assertEquals(ModelUtils.getSimpleRef(requestBodySchema.get$ref()), "updatePetWithForm_request");
|
||||
Assert.assertNotNull(openAPI.getComponents().getSchemas().get(ModelUtils.getSimpleRef(requestBodySchema.get$ref())));
|
||||
|
||||
Schema requestBodySchema2 = ModelUtils.unaliasSchema(openAPI, requestBodySchema);
|
||||
// get$ref is not null as unaliasSchem returns the schema with the last $ref to the actual schema
|
||||
Assert.assertNotNull(requestBodySchema2.get$ref());
|
||||
Assert.assertEquals(requestBodySchema2.get$ref(), "#/components/schemas/updatePetWithForm_request");
|
||||
|
||||
Schema requestBodySchema3 = ModelUtils.getReferencedSchema(openAPI, requestBodySchema);
|
||||
CodegenParameter codegenParameter = codegen.fromFormProperty("visitDate",
|
||||
(Schema) requestBodySchema3.getProperties().get("visitDate"), new HashSet<>());
|
||||
|
||||
Assert.assertEquals(codegenParameter.defaultValue, "1971-12-19T03:39:57-08:00");
|
||||
Assert.assertEquals(codegenParameter.getSchema(), null);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,43 @@
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
description: Test schema unalias
|
||||
types
|
||||
title: Api Documentation
|
||||
version: "1.0"
|
||||
servers:
|
||||
- url: /
|
||||
paths:
|
||||
/thingy/{date}:
|
||||
post:
|
||||
description: update with form data
|
||||
operationId: updatePetWithForm
|
||||
parameters:
|
||||
- description: A date path parameter
|
||||
explode: false
|
||||
in: path
|
||||
name: date
|
||||
required: true
|
||||
schema:
|
||||
default: 1969-12-31T16:00:00.000+00:00
|
||||
example: 2021-01-01
|
||||
format: date
|
||||
type: string
|
||||
style: simple
|
||||
requestBody:
|
||||
content:
|
||||
application/x-www-form-urlencoded:
|
||||
schema:
|
||||
$ref: '#/components/schemas/updatePetWithForm_request'
|
||||
responses:
|
||||
"405":
|
||||
description: Invalid input
|
||||
components:
|
||||
schemas:
|
||||
updatePetWithForm_request:
|
||||
properties:
|
||||
visitDate:
|
||||
default: 1971-12-19T03:39:57-08:00
|
||||
description: Updated last vist timestamp
|
||||
format: date-time
|
||||
type: string
|
||||
type: object
|
Loading…
x
Reference in New Issue
Block a user