Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1065,6 +1065,96 @@ private static Schema getSchemaFromContent(Content content) {
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.
*
Expand Down Expand Up @@ -1131,7 +1221,14 @@ public static Schema unaliasSchema(OpenAPI openAPI,
}
} 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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4125,4 +4125,29 @@ public void testResponseContentAndHeader() {
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);
}
}
Original file line number Diff line number Diff line change
@@ -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