From d1ca82cb8b71b8a08111463712bf53549dad2a91 Mon Sep 17 00:00:00 2001 From: William Cheng Date: Sat, 12 Oct 2024 16:12:23 +0800 Subject: [PATCH] auto fix self-reference schemas --- .../codegen/OpenAPINormalizer.java | 52 +++++++++++++++++++ .../languages/AbstractJavaCodegen.java | 4 +- .../src/test/resources/3_1/java/petstore.yaml | 21 ++++++++ .../okhttp-gson-3.1/.openapi-generator/FILES | 6 +++ .../petstore/java/okhttp-gson-3.1/README.md | 3 ++ .../java/okhttp-gson-3.1/api/openapi.yaml | 16 ++++++ .../java/org/openapitools/client/JSON.java | 3 ++ 7 files changed, 103 insertions(+), 2 deletions(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenAPINormalizer.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenAPINormalizer.java index acc09cc2a10..9875ffdafa5 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenAPINormalizer.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenAPINormalizer.java @@ -493,12 +493,64 @@ public class OpenAPINormalizer { } } + // auto fix self reference schema to avoid stack overflow + fixSelfReferenceSchema(schemaName, schema); + // normalize the schemas schemas.put(schemaName, normalizeSchema(schema, new HashSet<>())); } } } + /** + * Auto fix a self referencing schema using any type to replace the self-referencing sub-item. + * + * @param name Schema name + * @param schema Schema + */ + public void fixSelfReferenceSchema(String name, Schema schema) { + if (ModelUtils.isArraySchema(schema)) { + if (isSelfReference(name, schema.getItems())) { + LOGGER.error("Array schema {} has a sub-item referencing itself. Worked around the self-reference schema using any type instead.", name); + schema.setItems(new Schema<>()); + } + } + + if (ModelUtils.isOneOf(schema)) { + for (int i = 0; i < schema.getOneOf().size(); i++) { + if (isSelfReference(name, (Schema) schema.getOneOf().get(i))) { + LOGGER.error("oneOf schema {} has a sub-item referencing itself. Worked around the self-reference schema by removing it.", name); + schema.getOneOf().remove(i); + } + } + } + + if (ModelUtils.isAnyOf(schema)) { + for (int i = 0; i < schema.getAnyOf().size(); i++) { + if (isSelfReference(name, (Schema) schema.getAnyOf().get(i))) { + LOGGER.error("anyOf schema {} has a sub-item referencing itself. Worked around the self-reference schema by removing it.", name); + schema.getAnyOf().remove(i); + } + } + } + + if (schema.getAdditionalProperties() != null && schema.getAdditionalProperties() instanceof Schema) { + if (isSelfReference(name, (Schema) schema.getAdditionalProperties())) { + LOGGER.error("Schema {} (with additional properties) has a sub-item referencing itself. Worked around the self-reference schema using any type instead.", name); + schema.setAdditionalProperties(new Schema<>()); + } + } + + } + + private boolean isSelfReference(String name, Schema subSchema) { + if (subSchema != null && name.equals(ModelUtils.getSimpleRef(subSchema.get$ref()))) { + return true; + } else { + return false; + } + } + /** * Normalizes a schema * diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractJavaCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractJavaCodegen.java index 2a3836d94dc..e34cbee7799 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractJavaCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractJavaCodegen.java @@ -1493,7 +1493,7 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code MediaType mediaType = content.values().iterator().next(); if (mediaType.getExample() != null) { if (isModel) { - LOGGER.warn("Ignoring complex example on request body"); + once(LOGGER).warn("Ignoring complex example on request body"); } else { codegenParameter.example = mediaType.getExample().toString(); return; @@ -1504,7 +1504,7 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code Example example = mediaType.getExamples().values().iterator().next(); if (example.getValue() != null) { if (isModel) { - LOGGER.warn("Ignoring complex example on request body"); + once(LOGGER).warn("Ignoring complex example on request body"); } else { codegenParameter.example = example.getValue().toString(); return; diff --git a/modules/openapi-generator/src/test/resources/3_1/java/petstore.yaml b/modules/openapi-generator/src/test/resources/3_1/java/petstore.yaml index 5e4b2262805..e5f9b37429a 100644 --- a/modules/openapi-generator/src/test/resources/3_1/java/petstore.yaml +++ b/modules/openapi-generator/src/test/resources/3_1/java/petstore.yaml @@ -1066,3 +1066,24 @@ components: - $ref: '#/components/schemas/SimpleModelWithArrayProperty' myObject: type: object + SelfReference: + type: array + items: + $ref: "#/components/schemas/SelfReference" + SelfReferenceOneOf: + oneOf: + - type: string + - type: boolean + - $ref: "#/components/schemas/SelfReferenceOneOf" + SelfReferenceAnyOf: + anyOf: + - type: string + - type: boolean + - $ref: "#/components/schemas/SelfReferenceAnyOf" + SelfReferenceAdditionalProperties: + type: object + additionalProperties: + $ref: "#/components/schemas/SelfReferenceAdditionalProperties" + properties: + dummy: + type: string diff --git a/samples/client/petstore/java/okhttp-gson-3.1/.openapi-generator/FILES b/samples/client/petstore/java/okhttp-gson-3.1/.openapi-generator/FILES index 943f1a855f6..8215278225a 100644 --- a/samples/client/petstore/java/okhttp-gson-3.1/.openapi-generator/FILES +++ b/samples/client/petstore/java/okhttp-gson-3.1/.openapi-generator/FILES @@ -24,6 +24,9 @@ docs/Pet.md docs/PetApi.md docs/RefRefToPathLevelParameterOneofRefToOneofParameter.md docs/RefToRefParameterAnyofRefToAnyofParameter.md +docs/SelfReferenceAdditionalProperties.md +docs/SelfReferenceAnyOf.md +docs/SelfReferenceOneOf.md docs/SimpleModelWithArrayProperty.md docs/StoreApi.md docs/StringOrInt.md @@ -82,6 +85,9 @@ src/main/java/org/openapitools/client/model/Order.java src/main/java/org/openapitools/client/model/Pet.java src/main/java/org/openapitools/client/model/RefRefToPathLevelParameterOneofRefToOneofParameter.java src/main/java/org/openapitools/client/model/RefToRefParameterAnyofRefToAnyofParameter.java +src/main/java/org/openapitools/client/model/SelfReferenceAdditionalProperties.java +src/main/java/org/openapitools/client/model/SelfReferenceAnyOf.java +src/main/java/org/openapitools/client/model/SelfReferenceOneOf.java src/main/java/org/openapitools/client/model/SimpleModelWithArrayProperty.java src/main/java/org/openapitools/client/model/StringOrInt.java src/main/java/org/openapitools/client/model/Tag.java diff --git a/samples/client/petstore/java/okhttp-gson-3.1/README.md b/samples/client/petstore/java/okhttp-gson-3.1/README.md index cfa9bbf6198..5fe6938c9a4 100644 --- a/samples/client/petstore/java/okhttp-gson-3.1/README.md +++ b/samples/client/petstore/java/okhttp-gson-3.1/README.md @@ -166,6 +166,9 @@ Class | Method | HTTP request | Description - [Pet](docs/Pet.md) - [RefRefToPathLevelParameterOneofRefToOneofParameter](docs/RefRefToPathLevelParameterOneofRefToOneofParameter.md) - [RefToRefParameterAnyofRefToAnyofParameter](docs/RefToRefParameterAnyofRefToAnyofParameter.md) + - [SelfReferenceAdditionalProperties](docs/SelfReferenceAdditionalProperties.md) + - [SelfReferenceAnyOf](docs/SelfReferenceAnyOf.md) + - [SelfReferenceOneOf](docs/SelfReferenceOneOf.md) - [SimpleModelWithArrayProperty](docs/SimpleModelWithArrayProperty.md) - [StringOrInt](docs/StringOrInt.md) - [Tag](docs/Tag.md) diff --git a/samples/client/petstore/java/okhttp-gson-3.1/api/openapi.yaml b/samples/client/petstore/java/okhttp-gson-3.1/api/openapi.yaml index aabe501dcc3..4e559c33921 100644 --- a/samples/client/petstore/java/okhttp-gson-3.1/api/openapi.yaml +++ b/samples/client/petstore/java/okhttp-gson-3.1/api/openapi.yaml @@ -1160,6 +1160,22 @@ components: - $ref: '#/components/schemas/SimpleModelWithArrayProperty' myObject: type: object + SelfReference: + items: {} + type: array + SelfReferenceOneOf: + oneOf: + - type: string + - type: boolean + SelfReferenceAnyOf: + anyOf: + - type: string + - type: boolean + SelfReferenceAdditionalProperties: + additionalProperties: {} + properties: + dummy: + type: string updatePetWithForm_request: properties: name: diff --git a/samples/client/petstore/java/okhttp-gson-3.1/src/main/java/org/openapitools/client/JSON.java b/samples/client/petstore/java/okhttp-gson-3.1/src/main/java/org/openapitools/client/JSON.java index d0a1342c44c..6b9704505f2 100644 --- a/samples/client/petstore/java/okhttp-gson-3.1/src/main/java/org/openapitools/client/JSON.java +++ b/samples/client/petstore/java/okhttp-gson-3.1/src/main/java/org/openapitools/client/JSON.java @@ -137,6 +137,9 @@ public class JSON { gsonBuilder.registerTypeAdapterFactory(new org.openapitools.client.model.Pet.CustomTypeAdapterFactory()); gsonBuilder.registerTypeAdapterFactory(new org.openapitools.client.model.RefRefToPathLevelParameterOneofRefToOneofParameter.CustomTypeAdapterFactory()); gsonBuilder.registerTypeAdapterFactory(new org.openapitools.client.model.RefToRefParameterAnyofRefToAnyofParameter.CustomTypeAdapterFactory()); + gsonBuilder.registerTypeAdapterFactory(new org.openapitools.client.model.SelfReferenceAdditionalProperties.CustomTypeAdapterFactory()); + gsonBuilder.registerTypeAdapterFactory(new org.openapitools.client.model.SelfReferenceAnyOf.CustomTypeAdapterFactory()); + gsonBuilder.registerTypeAdapterFactory(new org.openapitools.client.model.SelfReferenceOneOf.CustomTypeAdapterFactory()); gsonBuilder.registerTypeAdapterFactory(new org.openapitools.client.model.SimpleModelWithArrayProperty.CustomTypeAdapterFactory()); gsonBuilder.registerTypeAdapterFactory(new org.openapitools.client.model.StringOrInt.CustomTypeAdapterFactory()); gsonBuilder.registerTypeAdapterFactory(new org.openapitools.client.model.Tag.CustomTypeAdapterFactory());