From 6a8769e83c9f866769c5fb73a7fd21d1b577b93a Mon Sep 17 00:00:00 2001 From: Alexej Date: Sat, 21 Mar 2020 23:33:15 +0100 Subject: [PATCH 01/16] Fix OpenAPITools#5381 added x-is-one-of-interface extension for oneOf interface in mustache template --- .../codegen/languages/SpringCodegen.java | 125 +++++++++++++++++- .../main/resources/JavaSpring/model.mustache | 2 +- .../JavaSpring/oneof_interface.mustache | 6 + 3 files changed, 130 insertions(+), 3 deletions(-) create mode 100644 modules/openapi-generator/src/main/resources/JavaSpring/oneof_interface.mustache diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java index 8450fbd5f4de..6c02e6553c23 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java @@ -21,6 +21,10 @@ import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.Operation; import io.swagger.v3.oas.models.PathItem; +import io.swagger.v3.oas.models.media.ComposedSchema; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.RequestBody; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.openapitools.codegen.*; import org.openapitools.codegen.languages.features.BeanValidationFeatures; @@ -29,6 +33,8 @@ import org.openapitools.codegen.meta.features.*; import org.openapitools.codegen.templating.mustache.SplitStringLambda; import org.openapitools.codegen.templating.mustache.TrimWhitespaceLambda; +import org.openapitools.codegen.utils.ModelUtils; +import org.openapitools.codegen.utils.OneOfImplementorAdditionalData; import org.openapitools.codegen.utils.URLPathUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -233,7 +239,7 @@ public void processOpts() { } super.processOpts(); - + useOneOfInterfaces = true; // clear model and api doc template as this codegen // does not support auto-generated markdown doc at the moment //TODO: add doc templates @@ -523,6 +529,58 @@ public void addOperationToGroup(String tag, String resourcePath, Operation opera } } + @Override + public void addOneOfInterfaceModel(ComposedSchema cs, String name) { + CodegenModel codegenModel = new CodegenModel(); + + for (Schema o : cs.getOneOf()) { + codegenModel.oneOf.add(toModelName(ModelUtils.getSimpleRef(o.get$ref()))); + } + codegenModel.name = name; + codegenModel.classname = name; + codegenModel.vendorExtensions.put("isOneOfInterface", true); + codegenModel.discriminator = createDiscriminator("", (Schema) cs); + codegenModel.interfaceModels = new ArrayList(); + + for(Schema schema : cs.getOneOf()){ + String[] split = schema.get$ref().split("/"); + String singleSchemaType = split[split.length-1]; + CodegenProperty codegenProperty = fromProperty(singleSchemaType, schema); + codegenProperty.setBaseName(singleSchemaType.toLowerCase(Locale.getDefault())); + codegenModel.vars.add(codegenProperty); + } + addOneOfInterfaces.add(codegenModel); + } + + @Override + public CodegenParameter fromRequestBody(RequestBody body, Set imports, String bodyParameterName) { + CodegenParameter codegenParameter = super.fromRequestBody(body, imports, bodyParameterName); + Schema schema = ModelUtils.getSchemaFromRequestBody(body); + CodegenProperty codegenProperty = fromProperty("property", schema); + + List oneOfClassNames = new ArrayList<>(); + if (codegenProperty != null && codegenProperty.getComplexType() != null && schema instanceof ComposedSchema) { + // will be set with imports.add(codegenParameter.baseType); in defaultcodegen + imports.clear(); + ComposedSchema composedSchema = (ComposedSchema) schema; + for(Schema oneOfSchema: composedSchema.getOneOf()){ + String[] split = oneOfSchema.get$ref().split("/"); + oneOfClassNames.add(split[split.length - 1]); + } + String codegenModelName = createOneOfClassName(oneOfClassNames); + imports.add(codegenModelName); + codegenParameter.baseName = codegenModelName; + codegenParameter.paramName = toParamName(codegenParameter.baseName); + codegenParameter.baseType = codegenParameter.baseName; + codegenParameter.dataType = getTypeDeclaration(codegenModelName); + codegenParameter.description = codegenProperty.getDescription(); + codegenProperty.setComplexType(codegenModelName); + codegenProperty.setBaseName(codegenModelName); + codegenProperty.setDatatype(codegenModelName); + } + return codegenParameter; + } + @Override public void preprocessOpenAPI(OpenAPI openAPI) { super.preprocessOpenAPI(openAPI); @@ -629,6 +687,57 @@ public void setReturnContainer(final String returnContainer) { return objs; } + @Override + public Map postProcessAllModels(Map objs) { + super.postProcessAllModels(objs); + Map additionalDataMap = new HashMap<>(); + for (Map.Entry modelsEntry : objs.entrySet()) { + Map modelsAttrs = (Map) modelsEntry.getValue(); + List models = (List) modelsAttrs.get("models"); + List> modelsImports = (List>) modelsAttrs + .getOrDefault("imports", new ArrayList>()); + for (Object _mo : models) { + Map mo = (Map) _mo; + CodegenModel cm = (CodegenModel) mo.get("model"); + if (cm.oneOf.size() > 0) { + cm.vendorExtensions.put("isOneOfInterface", true); + // if this is oneOf interface, make sure we include the necessary jackson imports for it + for (String classToImport : Arrays + .asList("JsonTypeInfo", "JsonSubTypes", "JsonProperty", + "ApiModelProperty")) { + Map i = new HashMap() {{ + put("import", importMapping.get(classToImport)); + }}; + if (!modelsImports.contains(i)) { + modelsImports.add(i); + } + } + List oneOfClassNames = new ArrayList<>(); + + for (String one : cm.oneOf) { + if (!additionalDataMap.containsKey(one)) { + additionalDataMap.put(one, new OneOfImplementorAdditionalData(one)); + additionalDataMap.get(one).addFromInterfaceModel(cm, modelsImports); + } + oneOfClassNames.add(one); + } + String codegenModelName = createOneOfClassName(oneOfClassNames); + cm.name = codegenModelName; + cm.classname = codegenModelName; + Object value = modelsEntry.getValue(); + objs.remove(modelsEntry.getKey()); + objs.put(codegenModelName, value); + } + } + } + return objs; + } + + private String createOneOfClassName(List oneOfClassNames) { + oneOfClassNames.sort(String::compareToIgnoreCase); + return "OneOf" + StringUtils.join(oneOfClassNames, ""); + } + private interface DataTypeAssigner { void setReturnType(String returnType); @@ -898,4 +1007,16 @@ public void postProcessParameter(CodegenParameter p) { } } -} + @Override + public void addImportsToOneOfInterface(List> imports) { + for (String i : Arrays.asList("JsonSubTypes", "JsonTypeInfo")) { + Map oneImport = new HashMap() {{ + put("import", importMapping.get(i)); + }}; + if (!imports.contains(oneImport)) { + imports.add(oneImport); + } + } + } + +} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/JavaSpring/model.mustache b/modules/openapi-generator/src/main/resources/JavaSpring/model.mustache index fbe3a9f1445d..3eadeffb3ace 100644 --- a/modules/openapi-generator/src/main/resources/JavaSpring/model.mustache +++ b/modules/openapi-generator/src/main/resources/JavaSpring/model.mustache @@ -35,7 +35,7 @@ import org.springframework.hateoas.RepresentationModel; {{>enumOuterClass}} {{/isEnum}} {{^isEnum}} -{{>pojo}} + {{#vendorExtensions.x-is-one-of-interface}}{{>oneof_interface}}{{/vendorExtensions.x-is-one-of-interface}}{{^vendorExtensions.x-is-one-of-interface}}{{>pojo}}{{/vendorExtensions.x-is-one-of-interface}} {{/isEnum}} {{/model}} {{/models}} diff --git a/modules/openapi-generator/src/main/resources/JavaSpring/oneof_interface.mustache b/modules/openapi-generator/src/main/resources/JavaSpring/oneof_interface.mustache new file mode 100644 index 000000000000..02deb483d5fd --- /dev/null +++ b/modules/openapi-generator/src/main/resources/JavaSpring/oneof_interface.mustache @@ -0,0 +1,6 @@ +{{>additionalModelTypeAnnotations}}{{>generatedAnnotation}}{{>typeInfoAnnotation}}{{>xmlAnnotation}} +public interface {{classname}} {{#vendorExtensions.x-implements}}{{#-first}}extends {{{.}}}{{/-first}}{{^-first}}, {{{.}}}{{/-first}}{{/vendorExtensions.x-implements}} { + {{#discriminator}} + public {{propertyType}} {{propertyGetter}}(); + {{/discriminator}} +} From 049359cded127c14c689f12921f36f544117c771 Mon Sep 17 00:00:00 2001 From: Alexej Date: Sun, 22 Mar 2020 09:06:32 +0100 Subject: [PATCH 02/16] Fix OpenAPITools#5381 fixed name of model from UNKNOWN_BASE_TYPE to right one in api: operationId + OneOf Fix OpenAPITools#5381 parcelableModel is not required --- .../main/java/org/openapitools/codegen/DefaultCodegen.java | 5 ++++- .../org/openapitools/codegen/languages/SpringCodegen.java | 6 ------ .../src/main/resources/JavaSpring/model.mustache | 2 +- .../src/main/resources/JavaSpring/oneof_interface.mustache | 2 +- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java index 2e5f4f405366..9dfce5afc65e 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java @@ -5425,6 +5425,9 @@ public CodegenParameter fromRequestBody(RequestBody body, Set imports, S LOGGER.warn("codegenModel is null. Default to UNKNOWN_BASE_TYPE"); codegenModelName = "UNKNOWN_BASE_TYPE"; codegenModelDescription = "UNKNOWN_DESCRIPTION"; + if (useOneOfInterfaces && templateDir.equals("JavaSpring")){ + codegenModelName = codegenProperty.getComplexType()+"OneOf"; + } } if (StringUtils.isEmpty(bodyParameterName)) { @@ -5439,7 +5442,7 @@ public CodegenParameter fromRequestBody(RequestBody body, Set imports, S codegenParameter.description = codegenModelDescription; imports.add(codegenParameter.baseType); - if (codegenProperty.complexType != null) { + if (codegenProperty.complexType != null && (useOneOfInterfaces && !templateDir.equals("JavaSpring"))) { imports.add(codegenProperty.complexType); } } diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java index 6c02e6553c23..272b87a3b534 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java @@ -21,10 +21,6 @@ import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.Operation; import io.swagger.v3.oas.models.PathItem; -import io.swagger.v3.oas.models.media.ComposedSchema; -import io.swagger.v3.oas.models.media.Schema; -import io.swagger.v3.oas.models.parameters.RequestBody; -import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.openapitools.codegen.*; import org.openapitools.codegen.languages.features.BeanValidationFeatures; @@ -33,8 +29,6 @@ import org.openapitools.codegen.meta.features.*; import org.openapitools.codegen.templating.mustache.SplitStringLambda; import org.openapitools.codegen.templating.mustache.TrimWhitespaceLambda; -import org.openapitools.codegen.utils.ModelUtils; -import org.openapitools.codegen.utils.OneOfImplementorAdditionalData; import org.openapitools.codegen.utils.URLPathUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/modules/openapi-generator/src/main/resources/JavaSpring/model.mustache b/modules/openapi-generator/src/main/resources/JavaSpring/model.mustache index 3eadeffb3ace..d412a1224e04 100644 --- a/modules/openapi-generator/src/main/resources/JavaSpring/model.mustache +++ b/modules/openapi-generator/src/main/resources/JavaSpring/model.mustache @@ -35,7 +35,7 @@ import org.springframework.hateoas.RepresentationModel; {{>enumOuterClass}} {{/isEnum}} {{^isEnum}} - {{#vendorExtensions.x-is-one-of-interface}}{{>oneof_interface}}{{/vendorExtensions.x-is-one-of-interface}}{{^vendorExtensions.x-is-one-of-interface}}{{>pojo}}{{/vendorExtensions.x-is-one-of-interface}} +{{#vendorExtensions.x-is-one-of-interface}}{{>oneof_interface}}{{/vendorExtensions.x-is-one-of-interface}}{{^vendorExtensions.x-is-one-of-interface}}{{>pojo}}{{/vendorExtensions.x-is-one-of-interface}} {{/isEnum}} {{/model}} {{/models}} diff --git a/modules/openapi-generator/src/main/resources/JavaSpring/oneof_interface.mustache b/modules/openapi-generator/src/main/resources/JavaSpring/oneof_interface.mustache index 02deb483d5fd..4500871766c1 100644 --- a/modules/openapi-generator/src/main/resources/JavaSpring/oneof_interface.mustache +++ b/modules/openapi-generator/src/main/resources/JavaSpring/oneof_interface.mustache @@ -3,4 +3,4 @@ public interface {{classname}} {{#vendorExtensions.x-implements}}{{#-first}}exte {{#discriminator}} public {{propertyType}} {{propertyGetter}}(); {{/discriminator}} -} +} \ No newline at end of file From 49f13ebc30340ff78d6e4a8459ead453015c5c22 Mon Sep 17 00:00:00 2001 From: Alexej Date: Sun, 22 Mar 2020 11:18:19 +0100 Subject: [PATCH 03/16] Fix OpenAPITools#5381 removed not needed methods --- .../codegen/languages/SpringCodegen.java | 103 ------------------ 1 file changed, 103 deletions(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java index 272b87a3b534..cad6828cd3fd 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java @@ -523,58 +523,6 @@ public void addOperationToGroup(String tag, String resourcePath, Operation opera } } - @Override - public void addOneOfInterfaceModel(ComposedSchema cs, String name) { - CodegenModel codegenModel = new CodegenModel(); - - for (Schema o : cs.getOneOf()) { - codegenModel.oneOf.add(toModelName(ModelUtils.getSimpleRef(o.get$ref()))); - } - codegenModel.name = name; - codegenModel.classname = name; - codegenModel.vendorExtensions.put("isOneOfInterface", true); - codegenModel.discriminator = createDiscriminator("", (Schema) cs); - codegenModel.interfaceModels = new ArrayList(); - - for(Schema schema : cs.getOneOf()){ - String[] split = schema.get$ref().split("/"); - String singleSchemaType = split[split.length-1]; - CodegenProperty codegenProperty = fromProperty(singleSchemaType, schema); - codegenProperty.setBaseName(singleSchemaType.toLowerCase(Locale.getDefault())); - codegenModel.vars.add(codegenProperty); - } - addOneOfInterfaces.add(codegenModel); - } - - @Override - public CodegenParameter fromRequestBody(RequestBody body, Set imports, String bodyParameterName) { - CodegenParameter codegenParameter = super.fromRequestBody(body, imports, bodyParameterName); - Schema schema = ModelUtils.getSchemaFromRequestBody(body); - CodegenProperty codegenProperty = fromProperty("property", schema); - - List oneOfClassNames = new ArrayList<>(); - if (codegenProperty != null && codegenProperty.getComplexType() != null && schema instanceof ComposedSchema) { - // will be set with imports.add(codegenParameter.baseType); in defaultcodegen - imports.clear(); - ComposedSchema composedSchema = (ComposedSchema) schema; - for(Schema oneOfSchema: composedSchema.getOneOf()){ - String[] split = oneOfSchema.get$ref().split("/"); - oneOfClassNames.add(split[split.length - 1]); - } - String codegenModelName = createOneOfClassName(oneOfClassNames); - imports.add(codegenModelName); - codegenParameter.baseName = codegenModelName; - codegenParameter.paramName = toParamName(codegenParameter.baseName); - codegenParameter.baseType = codegenParameter.baseName; - codegenParameter.dataType = getTypeDeclaration(codegenModelName); - codegenParameter.description = codegenProperty.getDescription(); - codegenProperty.setComplexType(codegenModelName); - codegenProperty.setBaseName(codegenModelName); - codegenProperty.setDatatype(codegenModelName); - } - return codegenParameter; - } - @Override public void preprocessOpenAPI(OpenAPI openAPI) { super.preprocessOpenAPI(openAPI); @@ -681,57 +629,6 @@ public void setReturnContainer(final String returnContainer) { return objs; } - @Override - public Map postProcessAllModels(Map objs) { - super.postProcessAllModels(objs); - Map additionalDataMap = new HashMap<>(); - for (Map.Entry modelsEntry : objs.entrySet()) { - Map modelsAttrs = (Map) modelsEntry.getValue(); - List models = (List) modelsAttrs.get("models"); - List> modelsImports = (List>) modelsAttrs - .getOrDefault("imports", new ArrayList>()); - for (Object _mo : models) { - Map mo = (Map) _mo; - CodegenModel cm = (CodegenModel) mo.get("model"); - if (cm.oneOf.size() > 0) { - cm.vendorExtensions.put("isOneOfInterface", true); - // if this is oneOf interface, make sure we include the necessary jackson imports for it - for (String classToImport : Arrays - .asList("JsonTypeInfo", "JsonSubTypes", "JsonProperty", - "ApiModelProperty")) { - Map i = new HashMap() {{ - put("import", importMapping.get(classToImport)); - }}; - if (!modelsImports.contains(i)) { - modelsImports.add(i); - } - } - List oneOfClassNames = new ArrayList<>(); - - for (String one : cm.oneOf) { - if (!additionalDataMap.containsKey(one)) { - additionalDataMap.put(one, new OneOfImplementorAdditionalData(one)); - additionalDataMap.get(one).addFromInterfaceModel(cm, modelsImports); - } - oneOfClassNames.add(one); - } - String codegenModelName = createOneOfClassName(oneOfClassNames); - cm.name = codegenModelName; - cm.classname = codegenModelName; - Object value = modelsEntry.getValue(); - objs.remove(modelsEntry.getKey()); - objs.put(codegenModelName, value); - } - } - } - return objs; - } - - private String createOneOfClassName(List oneOfClassNames) { - oneOfClassNames.sort(String::compareToIgnoreCase); - return "OneOf" + StringUtils.join(oneOfClassNames, ""); - } - private interface DataTypeAssigner { void setReturnType(String returnType); From 1a5a48490c44821e33bd76eca0985502df0b7f57 Mon Sep 17 00:00:00 2001 From: Alexej Date: Sun, 22 Mar 2020 12:03:38 +0100 Subject: [PATCH 04/16] Fix OpenAPITools#5381 catch NPE cases in preprocessOpenAPI updated samples --- .../org/openapitools/codegen/DefaultCodegen.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java index 9dfce5afc65e..2f0768bb3859 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java @@ -710,7 +710,7 @@ public void postProcessParameter(CodegenParameter parameter) { //override with any special handling of the entire OpenAPI spec document @SuppressWarnings("unused") public void preprocessOpenAPI(OpenAPI openAPI) { - if (useOneOfInterfaces) { + if (useOneOfInterfaces && openAPI.getComponents() != null) { // we process the openapi schema here to find oneOf schemas and create interface models for them Map schemas = new HashMap(openAPI.getComponents().getSchemas()); if (schemas == null) { @@ -733,11 +733,13 @@ public void preprocessOpenAPI(OpenAPI openAPI) { schemas.put(opId, requestSchema); } // process all response bodies - for (Map.Entry ar : op.getValue().getResponses().entrySet()) { - ApiResponse a = ModelUtils.getReferencedApiResponse(openAPI, ar.getValue()); - Schema responseSchema = ModelUtils.getSchemaFromResponse(a); - if (responseSchema != null) { - schemas.put(opId + ar.getKey(), responseSchema); + if (op.getValue().getResponses() != null){ + for (Map.Entry ar : op.getValue().getResponses().entrySet()) { + ApiResponse a = ModelUtils.getReferencedApiResponse(openAPI, ar.getValue()); + Schema responseSchema = ModelUtils.getSchemaFromResponse(a); + if (responseSchema != null) { + schemas.put(opId + ar.getKey(), responseSchema); + } } } } From 48a1a4a71737d187c74d1627d6a40c8b66cc0018 Mon Sep 17 00:00:00 2001 From: Alexej Date: Tue, 24 Mar 2020 22:14:59 +0100 Subject: [PATCH 05/16] Fix OpenAPITools#5381 fixed generation of oneOf Models --- .../src/main/java/org/openapitools/codegen/DefaultCodegen.java | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java index 2f0768bb3859..e9d57285f03a 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java @@ -753,6 +753,7 @@ public void preprocessOpenAPI(OpenAPI openAPI) { String nOneOf = toModelName(n + "OneOf"); if (ModelUtils.isComposedSchema(s)) { addOneOfNameExtension((ComposedSchema) s, n); + addOneOfInterfaceModel((ComposedSchema) s, nOneOf); } else if (ModelUtils.isArraySchema(s)) { Schema items = ((ArraySchema) s).getItems(); if (ModelUtils.isComposedSchema(items)) { From a8113301b983b42d5b26ca073b70fe9291260fbb Mon Sep 17 00:00:00 2001 From: Alexej Date: Tue, 24 Mar 2020 23:18:48 +0100 Subject: [PATCH 06/16] Fix OpenAPITools#5381 addOneOfInterfaceModel only for cases when useOneOfInterfaces is true and for spring --- .../main/java/org/openapitools/codegen/DefaultCodegen.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java index e9d57285f03a..68de3d85e27b 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java @@ -753,7 +753,9 @@ public void preprocessOpenAPI(OpenAPI openAPI) { String nOneOf = toModelName(n + "OneOf"); if (ModelUtils.isComposedSchema(s)) { addOneOfNameExtension((ComposedSchema) s, n); - addOneOfInterfaceModel((ComposedSchema) s, nOneOf); + if (useOneOfInterfaces && templateDir.equals("JavaSpring")){ + addOneOfInterfaceModel((ComposedSchema) s, nOneOf); + } } else if (ModelUtils.isArraySchema(s)) { Schema items = ((ArraySchema) s).getItems(); if (ModelUtils.isComposedSchema(items)) { From 299cdb38a21422ec71f0925dce2fe974255d2123 Mon Sep 17 00:00:00 2001 From: Alexej Date: Tue, 24 Mar 2020 23:55:30 +0100 Subject: [PATCH 07/16] Fix OpenAPITools#5381 NPE fix --- .../src/main/java/org/openapitools/codegen/DefaultCodegen.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java index 68de3d85e27b..239915f786cb 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java @@ -753,7 +753,7 @@ public void preprocessOpenAPI(OpenAPI openAPI) { String nOneOf = toModelName(n + "OneOf"); if (ModelUtils.isComposedSchema(s)) { addOneOfNameExtension((ComposedSchema) s, n); - if (useOneOfInterfaces && templateDir.equals("JavaSpring")){ + if (useOneOfInterfaces && "JavaSpring".equals(templateDir)){ addOneOfInterfaceModel((ComposedSchema) s, nOneOf); } } else if (ModelUtils.isArraySchema(s)) { From 26a95f637d08a5a0e346a91d339b58047f44aa24 Mon Sep 17 00:00:00 2001 From: Alexej Date: Wed, 25 Mar 2020 11:06:08 +0100 Subject: [PATCH 08/16] Fix OpenAPITools#5381 spring: fixed use of oneOf Models in API --- .../openapitools/codegen/DefaultCodegen.java | 47 +++++++++++++++---- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java index f5538a6f9c80..cbe2f03f6b6a 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java @@ -83,6 +83,7 @@ public class DefaultCodegen implements CodegenConfig { private static final Logger LOGGER = LoggerFactory.getLogger(DefaultCodegen.class); public static FeatureSet DefaultFeatureSet; + public static final String LIBRARY_ONEOF_IMPL = "JavaSpring"; // A cache of sanitized words. The sanitizeName() method is invoked many times with the same // arguments, this cache is used to optimized performance. @@ -710,7 +711,7 @@ public void postProcessParameter(CodegenParameter parameter) { //override with any special handling of the entire OpenAPI spec document @SuppressWarnings("unused") public void preprocessOpenAPI(OpenAPI openAPI) { - if (useOneOfInterfaces) { + if (useOneOfInterfaces && openAPI.getComponents() != null) { // we process the openapi schema here to find oneOf schemas and create interface models for them Map schemas = new HashMap(openAPI.getComponents().getSchemas()); if (schemas == null) { @@ -733,24 +734,42 @@ public void preprocessOpenAPI(OpenAPI openAPI) { schemas.put(opId, requestSchema); } // process all response bodies - for (Map.Entry ar : op.getValue().getResponses().entrySet()) { - ApiResponse a = ModelUtils.getReferencedApiResponse(openAPI, ar.getValue()); - Schema responseSchema = ModelUtils.getSchemaFromResponse(a); - if (responseSchema != null) { - schemas.put(opId + ar.getKey(), responseSchema); + if (op.getValue().getResponses() != null) { + for (Map.Entry ar : op.getValue().getResponses() + .entrySet()) { + ApiResponse a = ModelUtils + .getReferencedApiResponse(openAPI, ar.getValue()); + Schema responseSchema = ModelUtils.getSchemaFromResponse(a); + if (responseSchema != null) { + schemas.put(opId + ar.getKey(), responseSchema); + } } } } } } + // also add all properties of all schemas to be checked for oneOf + Map propertySchemas = new HashMap(); + for (Map.Entry e : schemas.entrySet()) { + Schema s = e.getValue(); + Map props = s.getProperties(); + if (props == null) { + props = new HashMap(); + } + for (Map.Entry p : props.entrySet()) { + propertySchemas.put(e.getKey() + "/" + p.getKey(), p.getValue()); + } + } + schemas.putAll(propertySchemas); + // go through all gathered schemas and add them as interfaces to be created for (Map.Entry e : schemas.entrySet()) { String n = toModelName(e.getKey()); Schema s = e.getValue(); String nOneOf = toModelName(n + "OneOf"); if (ModelUtils.isComposedSchema(s)) { - if (e.getKey().contains("/")) { + if (e.getKey().contains("/") || (useOneOfInterfaces && LIBRARY_ONEOF_IMPL.equals(templateDir))) { // if this is property schema, we also need to generate the oneOf interface model addOneOfNameExtension((ComposedSchema) s, nOneOf); addOneOfInterfaceModel((ComposedSchema) s, nOneOf); @@ -5432,6 +5451,9 @@ public CodegenParameter fromRequestBody(RequestBody body, Set imports, S LOGGER.warn("codegenModel is null. Default to UNKNOWN_BASE_TYPE"); codegenModelName = "UNKNOWN_BASE_TYPE"; codegenModelDescription = "UNKNOWN_DESCRIPTION"; + if (useOneOfInterfaces && templateDir.equals(LIBRARY_ONEOF_IMPL)){ + codegenModelName = codegenProperty.getComplexType(); + } } if (StringUtils.isEmpty(bodyParameterName)) { @@ -5446,7 +5468,8 @@ public CodegenParameter fromRequestBody(RequestBody body, Set imports, S codegenParameter.description = codegenModelDescription; imports.add(codegenParameter.baseType); - if (codegenProperty.complexType != null) { + if (codegenProperty.complexType != null && (useOneOfInterfaces && !templateDir.equals( + LIBRARY_ONEOF_IMPL))) { imports.add(codegenProperty.complexType); } } @@ -5733,15 +5756,19 @@ public void addOneOfNameExtension(ComposedSchema s, String name) { } /** - * Add a given ComposedSchema as an interface model to be generated + * Add a given ComposedSchema as an interface model to be generated, assuming it has `oneOf` defined * @param cs ComposedSchema object to create as interface model * @param type name to use for the generated interface model */ public void addOneOfInterfaceModel(ComposedSchema cs, String type) { + if (cs.getOneOf() == null) { + return; + } CodegenModel cm = new CodegenModel(); cm.discriminator = createDiscriminator("", (Schema) cs); - for (Schema o : cs.getOneOf()) { + + for (Schema o : Optional.ofNullable(cs.getOneOf()).orElse(Collections.emptyList())) { if (o.get$ref() == null) { if (cm.discriminator != null && o.get$ref() == null) { // OpenAPI spec states that inline objects should not be considered when discriminator is used From 9af7db65ce8022654ff5a5ee111bd4bdfc6994c2 Mon Sep 17 00:00:00 2001 From: Alexej Date: Mon, 30 Mar 2020 21:22:56 +0200 Subject: [PATCH 09/16] Fix OpenAPITools#5381 implementing oneOf for spring lib overriding methods with different behavior from default --- .../openapitools/codegen/DefaultCodegen.java | 40 +++++++++++-------- .../codegen/languages/SpringCodegen.java | 31 ++++++++++++++ 2 files changed, 55 insertions(+), 16 deletions(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java index cbe2f03f6b6a..ef771f6bb1eb 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java @@ -83,7 +83,6 @@ public class DefaultCodegen implements CodegenConfig { private static final Logger LOGGER = LoggerFactory.getLogger(DefaultCodegen.class); public static FeatureSet DefaultFeatureSet; - public static final String LIBRARY_ONEOF_IMPL = "JavaSpring"; // A cache of sanitized words. The sanitizeName() method is invoked many times with the same // arguments, this cache is used to optimized performance. @@ -769,14 +768,7 @@ public void preprocessOpenAPI(OpenAPI openAPI) { Schema s = e.getValue(); String nOneOf = toModelName(n + "OneOf"); if (ModelUtils.isComposedSchema(s)) { - if (e.getKey().contains("/") || (useOneOfInterfaces && LIBRARY_ONEOF_IMPL.equals(templateDir))) { - // if this is property schema, we also need to generate the oneOf interface model - addOneOfNameExtension((ComposedSchema) s, nOneOf); - addOneOfInterfaceModel((ComposedSchema) s, nOneOf); - } else { - // else this is a component schema, so we will just use that as the oneOf interface model - addOneOfNameExtension((ComposedSchema) s, n); - } + addOneOfForComposedSchema(e, n, (ComposedSchema) s, nOneOf); } else if (ModelUtils.isArraySchema(s)) { Schema items = ((ArraySchema) s).getItems(); if (ModelUtils.isComposedSchema(items)) { @@ -794,6 +786,18 @@ public void preprocessOpenAPI(OpenAPI openAPI) { } } + protected void addOneOfForComposedSchema(Entry stringSchemaEntry, String modelName, ComposedSchema composedSchema, + String nOneOf) { + if (stringSchemaEntry.getKey().contains("/")) { + // if this is property schema, we also need to generate the oneOf interface model + addOneOfNameExtension(composedSchema, nOneOf); + addOneOfInterfaceModel(composedSchema, nOneOf); + } else { + // else this is a component schema, so we will just use that as the oneOf interface model + addOneOfNameExtension(composedSchema, modelName); + } + } + // override with any special handling of the entire OpenAPI spec document @SuppressWarnings("unused") public void processOpenAPI(OpenAPI openAPI) { @@ -5449,11 +5453,8 @@ public CodegenParameter fromRequestBody(RequestBody body, Set imports, S "'application/x-www-form-urlencoded' or 'multipart/?'"); LOGGER.warn("schema: " + schema); LOGGER.warn("codegenModel is null. Default to UNKNOWN_BASE_TYPE"); - codegenModelName = "UNKNOWN_BASE_TYPE"; codegenModelDescription = "UNKNOWN_DESCRIPTION"; - if (useOneOfInterfaces && templateDir.equals(LIBRARY_ONEOF_IMPL)){ - codegenModelName = codegenProperty.getComplexType(); - } + codegenModelName = getCodegenModelName(codegenProperty); } if (StringUtils.isEmpty(bodyParameterName)) { @@ -5468,9 +5469,8 @@ public CodegenParameter fromRequestBody(RequestBody body, Set imports, S codegenParameter.description = codegenModelDescription; imports.add(codegenParameter.baseType); - if (codegenProperty.complexType != null && (useOneOfInterfaces && !templateDir.equals( - LIBRARY_ONEOF_IMPL))) { - imports.add(codegenProperty.complexType); + if (codegenProperty.complexType != null) { + addAdditionalImports(imports, codegenProperty.complexType); } } } @@ -5519,6 +5519,14 @@ public CodegenParameter fromRequestBody(RequestBody body, Set imports, S return codegenParameter; } + protected void addAdditionalImports(Set imports, String complexType) { + imports.add(complexType); + } + + protected String getCodegenModelName(CodegenProperty codegenProperty) { + return "UNKNOWN_BASE_TYPE"; + } + protected void addOption(String key, String description, String defaultValue) { CliOption option = new CliOption(key, description); if (defaultValue != null) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java index cad6828cd3fd..aeaea6b09f66 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java @@ -21,6 +21,9 @@ import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.Operation; import io.swagger.v3.oas.models.PathItem; +import io.swagger.v3.oas.models.media.ComposedSchema; +import io.swagger.v3.oas.models.media.Schema; +import java.util.Map.Entry; import org.apache.commons.lang3.tuple.Pair; import org.openapitools.codegen.*; import org.openapitools.codegen.languages.features.BeanValidationFeatures; @@ -581,6 +584,34 @@ public void preprocessOpenAPI(OpenAPI openAPI) { } } + @Override + protected void addOneOfForComposedSchema(Entry stringSchemaEntry, String modelName, ComposedSchema composedSchema, + String nOneOf){ + if (useOneOfInterfaces) { + // if this is property schema, we also need to generate the oneOf interface model + addOneOfNameExtension(composedSchema, nOneOf); + addOneOfInterfaceModel(composedSchema, nOneOf); + } else { + super.addOneOfForComposedSchema(stringSchemaEntry, modelName, composedSchema, nOneOf); + } + } + + @Override + protected String getCodegenModelName(CodegenProperty codegenProperty) { + if (useOneOfInterfaces){ + return codegenProperty.getComplexType(); + } else { + return super.getCodegenModelName(codegenProperty); + } + } + + @Override + protected void addAdditionalImports(Set imports, String complexType) { + if (!useOneOfInterfaces){ + super.addAdditionalImports(imports, complexType); + } + } + @Override public Map postProcessOperationsWithModels(Map objs, List allModels) { Map operations = (Map) objs.get("operations"); From fbfd57d0effa2f4b17a32f83c2bc291023d2f449 Mon Sep 17 00:00:00 2001 From: Alexej Date: Sat, 21 Mar 2020 23:33:15 +0100 Subject: [PATCH 10/16] Fix OpenAPITools#5381 added x-is-one-of-interface extension for oneOf interface in mustache template --- .../java/org/openapitools/codegen/languages/SpringCodegen.java | 3 --- .../src/main/resources/JavaSpring/oneof_interface.mustache | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java index aeaea6b09f66..079f1d8c0591 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java @@ -21,9 +21,6 @@ import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.Operation; import io.swagger.v3.oas.models.PathItem; -import io.swagger.v3.oas.models.media.ComposedSchema; -import io.swagger.v3.oas.models.media.Schema; -import java.util.Map.Entry; import org.apache.commons.lang3.tuple.Pair; import org.openapitools.codegen.*; import org.openapitools.codegen.languages.features.BeanValidationFeatures; diff --git a/modules/openapi-generator/src/main/resources/JavaSpring/oneof_interface.mustache b/modules/openapi-generator/src/main/resources/JavaSpring/oneof_interface.mustache index 4500871766c1..02deb483d5fd 100644 --- a/modules/openapi-generator/src/main/resources/JavaSpring/oneof_interface.mustache +++ b/modules/openapi-generator/src/main/resources/JavaSpring/oneof_interface.mustache @@ -3,4 +3,4 @@ public interface {{classname}} {{#vendorExtensions.x-implements}}{{#-first}}exte {{#discriminator}} public {{propertyType}} {{propertyGetter}}(); {{/discriminator}} -} \ No newline at end of file +} From bfab3044e509ce60de669c893c47517ca74e9abf Mon Sep 17 00:00:00 2001 From: Alexej Date: Sun, 22 Mar 2020 09:06:32 +0100 Subject: [PATCH 11/16] Fix OpenAPITools#5381 fixed name of model from UNKNOWN_BASE_TYPE to right one in api: operationId + OneOf Fix OpenAPITools#5381 removed not needed methods Fix OpenAPITools#5381 fixed generation of oneOf Models Fix OpenAPITools#5381 addOneOfInterfaceModel only for cases when useOneOfInterfaces is true and for spring Fix OpenAPITools#5381 NPE fix for tests --- .../openapitools/codegen/DefaultCodegen.java | 39 +++---------------- .../JavaSpring/oneof_interface.mustache | 2 +- 2 files changed, 7 insertions(+), 34 deletions(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java index ef771f6bb1eb..ad52150bd999 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java @@ -748,27 +748,16 @@ public void preprocessOpenAPI(OpenAPI openAPI) { } } - // also add all properties of all schemas to be checked for oneOf - Map propertySchemas = new HashMap(); - for (Map.Entry e : schemas.entrySet()) { - Schema s = e.getValue(); - Map props = s.getProperties(); - if (props == null) { - props = new HashMap(); - } - for (Map.Entry p : props.entrySet()) { - propertySchemas.put(e.getKey() + "/" + p.getKey(), p.getValue()); - } - } - schemas.putAll(propertySchemas); - // go through all gathered schemas and add them as interfaces to be created for (Map.Entry e : schemas.entrySet()) { String n = toModelName(e.getKey()); Schema s = e.getValue(); String nOneOf = toModelName(n + "OneOf"); if (ModelUtils.isComposedSchema(s)) { - addOneOfForComposedSchema(e, n, (ComposedSchema) s, nOneOf); + addOneOfNameExtension((ComposedSchema) s, n); + if (useOneOfInterfaces && "JavaSpring".equals(templateDir)){ + addOneOfInterfaceModel((ComposedSchema) s, nOneOf); + } } else if (ModelUtils.isArraySchema(s)) { Schema items = ((ArraySchema) s).getItems(); if (ModelUtils.isComposedSchema(items)) { @@ -786,18 +775,6 @@ public void preprocessOpenAPI(OpenAPI openAPI) { } } - protected void addOneOfForComposedSchema(Entry stringSchemaEntry, String modelName, ComposedSchema composedSchema, - String nOneOf) { - if (stringSchemaEntry.getKey().contains("/")) { - // if this is property schema, we also need to generate the oneOf interface model - addOneOfNameExtension(composedSchema, nOneOf); - addOneOfInterfaceModel(composedSchema, nOneOf); - } else { - // else this is a component schema, so we will just use that as the oneOf interface model - addOneOfNameExtension(composedSchema, modelName); - } - } - // override with any special handling of the entire OpenAPI spec document @SuppressWarnings("unused") public void processOpenAPI(OpenAPI openAPI) { @@ -5764,19 +5741,15 @@ public void addOneOfNameExtension(ComposedSchema s, String name) { } /** - * Add a given ComposedSchema as an interface model to be generated, assuming it has `oneOf` defined + * Add a given ComposedSchema as an interface model to be generated * @param cs ComposedSchema object to create as interface model * @param type name to use for the generated interface model */ public void addOneOfInterfaceModel(ComposedSchema cs, String type) { - if (cs.getOneOf() == null) { - return; - } CodegenModel cm = new CodegenModel(); cm.discriminator = createDiscriminator("", (Schema) cs); - - for (Schema o : Optional.ofNullable(cs.getOneOf()).orElse(Collections.emptyList())) { + for (Schema o : cs.getOneOf()) { if (o.get$ref() == null) { if (cm.discriminator != null && o.get$ref() == null) { // OpenAPI spec states that inline objects should not be considered when discriminator is used diff --git a/modules/openapi-generator/src/main/resources/JavaSpring/oneof_interface.mustache b/modules/openapi-generator/src/main/resources/JavaSpring/oneof_interface.mustache index 02deb483d5fd..4500871766c1 100644 --- a/modules/openapi-generator/src/main/resources/JavaSpring/oneof_interface.mustache +++ b/modules/openapi-generator/src/main/resources/JavaSpring/oneof_interface.mustache @@ -3,4 +3,4 @@ public interface {{classname}} {{#vendorExtensions.x-implements}}{{#-first}}exte {{#discriminator}} public {{propertyType}} {{propertyGetter}}(); {{/discriminator}} -} +} \ No newline at end of file From 29003d8f99d655ada5f783ed13fe0e6359777e36 Mon Sep 17 00:00:00 2001 From: Alexej Date: Wed, 1 Apr 2020 21:22:46 +0200 Subject: [PATCH 12/16] Fix OpenAPITools#5381 fixed handing of composed schema with array --- .../openapitools/codegen/DefaultCodegen.java | 56 ++++++++++++++----- .../codegen/languages/SpringCodegen.java | 30 +++++----- 2 files changed, 57 insertions(+), 29 deletions(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java index ad52150bd999..cb2142b6ebdf 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java @@ -748,24 +748,34 @@ public void preprocessOpenAPI(OpenAPI openAPI) { } } - // go through all gathered schemas and add them as interfaces to be created + // also add all properties of all schemas to be checked for oneOf + Map propertySchemas = new HashMap(); for (Map.Entry e : schemas.entrySet()) { - String n = toModelName(e.getKey()); Schema s = e.getValue(); - String nOneOf = toModelName(n + "OneOf"); - if (ModelUtils.isComposedSchema(s)) { - addOneOfNameExtension((ComposedSchema) s, n); - if (useOneOfInterfaces && "JavaSpring".equals(templateDir)){ - addOneOfInterfaceModel((ComposedSchema) s, nOneOf); - } - } else if (ModelUtils.isArraySchema(s)) { - Schema items = ((ArraySchema) s).getItems(); + Map props = s.getProperties(); + if (props == null) { + props = new HashMap(); + } + for (Map.Entry p : props.entrySet()) { + propertySchemas.put(e.getKey() + "/" + p.getKey(), p.getValue()); + } + } + schemas.putAll(propertySchemas); + + // go through all gathered schemas and add them as interfaces to be created + for (Map.Entry e : schemas.entrySet()) { + String modelName = toModelName(e.getKey()); + Schema schema = e.getValue(); + String nOneOf = toModelName(modelName + "OneOf"); + if (ModelUtils.isComposedSchema(schema)) { + addOneOfForComposedSchema(e, modelName, (ComposedSchema) schema, nOneOf); + } else if (ModelUtils.isArraySchema(schema)) { + Schema items = ((ArraySchema) schema).getItems(); if (ModelUtils.isComposedSchema(items)) { - addOneOfNameExtension((ComposedSchema) items, nOneOf); - addOneOfInterfaceModel((ComposedSchema) items, nOneOf); + addOneOfForComposedSchemaArray(nOneOf, modelName, (ComposedSchema) items); } - } else if (ModelUtils.isMapSchema(s)) { - Schema addProps = ModelUtils.getAdditionalProperties(s); + } else if (ModelUtils.isMapSchema(schema)) { + Schema addProps = ModelUtils.getAdditionalProperties(schema); if (addProps != null && ModelUtils.isComposedSchema(addProps)) { addOneOfNameExtension((ComposedSchema) addProps, nOneOf); addOneOfInterfaceModel((ComposedSchema) addProps, nOneOf); @@ -775,6 +785,24 @@ public void preprocessOpenAPI(OpenAPI openAPI) { } } + protected void addOneOfForComposedSchemaArray(String nOneOf, String modelName, + ComposedSchema items) { + addOneOfNameExtension(items, nOneOf); + addOneOfInterfaceModel(items, nOneOf); + } + + protected void addOneOfForComposedSchema(Entry stringSchemaEntry, String modelName, ComposedSchema composedSchema, + String nOneOf) { + if (stringSchemaEntry.getKey().contains("/")) { + // if this is property schema, we also need to generate the oneOf interface model + addOneOfNameExtension(composedSchema, nOneOf); + addOneOfInterfaceModel(composedSchema, nOneOf); + } else { + // else this is a component schema, so we will just use that as the oneOf interface model + addOneOfNameExtension(composedSchema, modelName); + } + } + // override with any special handling of the entire OpenAPI spec document @SuppressWarnings("unused") public void processOpenAPI(OpenAPI openAPI) { diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java index 079f1d8c0591..c843398930e2 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java @@ -21,6 +21,9 @@ import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.Operation; import io.swagger.v3.oas.models.PathItem; +import io.swagger.v3.oas.models.media.ComposedSchema; +import io.swagger.v3.oas.models.media.Schema; +import java.util.Map.Entry; import org.apache.commons.lang3.tuple.Pair; import org.openapitools.codegen.*; import org.openapitools.codegen.languages.features.BeanValidationFeatures; @@ -584,29 +587,26 @@ public void preprocessOpenAPI(OpenAPI openAPI) { @Override protected void addOneOfForComposedSchema(Entry stringSchemaEntry, String modelName, ComposedSchema composedSchema, String nOneOf){ - if (useOneOfInterfaces) { - // if this is property schema, we also need to generate the oneOf interface model - addOneOfNameExtension(composedSchema, nOneOf); - addOneOfInterfaceModel(composedSchema, nOneOf); - } else { - super.addOneOfForComposedSchema(stringSchemaEntry, modelName, composedSchema, nOneOf); - } + // if this is property schema, we also need to generate the oneOf interface model + addOneOfNameExtension(composedSchema, modelName); + addOneOfInterfaceModel(composedSchema, modelName); + } + + @Override + protected void addOneOfForComposedSchemaArray(String nOneOf, String modelName, + ComposedSchema items) { + addOneOfNameExtension(items, modelName); + addOneOfInterfaceModel(items, modelName); } @Override protected String getCodegenModelName(CodegenProperty codegenProperty) { - if (useOneOfInterfaces){ - return codegenProperty.getComplexType(); - } else { - return super.getCodegenModelName(codegenProperty); - } + return codegenProperty.getComplexType(); } @Override protected void addAdditionalImports(Set imports, String complexType) { - if (!useOneOfInterfaces){ - super.addAdditionalImports(imports, complexType); - } + //nothing to do for spring } @Override From d8648310ba535838eaeca534e255adacfbe4c756 Mon Sep 17 00:00:00 2001 From: Alexej Date: Wed, 1 Apr 2020 22:13:53 +0200 Subject: [PATCH 13/16] Fix OpenAPITools#5381 fixed NPE in addOneOfInterfaceModel --- .../openapitools/codegen/DefaultCodegen.java | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java index cb2142b6ebdf..71a5055a0e6e 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java @@ -5777,18 +5777,20 @@ public void addOneOfInterfaceModel(ComposedSchema cs, String type) { CodegenModel cm = new CodegenModel(); cm.discriminator = createDiscriminator("", (Schema) cs); - for (Schema o : cs.getOneOf()) { - if (o.get$ref() == null) { - if (cm.discriminator != null && o.get$ref() == null) { - // OpenAPI spec states that inline objects should not be considered when discriminator is used - // https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#discriminatorObject - LOGGER.warn("Ignoring inline object in oneOf definition of {}, since discriminator is used", type); - } else { - LOGGER.warn("Inline models are not supported in oneOf definition right now"); + if (cs.getOneOf() != null){ + for (Schema o : cs.getOneOf()) { + if (o.get$ref() == null) { + if (cm.discriminator != null && o.get$ref() == null) { + // OpenAPI spec states that inline objects should not be considered when discriminator is used + // https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#discriminatorObject + LOGGER.warn("Ignoring inline object in oneOf definition of {}, since discriminator is used", type); + } else { + LOGGER.warn("Inline models are not supported in oneOf definition right now"); + } + continue; } - continue; + cm.oneOf.add(toModelName(ModelUtils.getSimpleRef(o.get$ref()))); } - cm.oneOf.add(toModelName(ModelUtils.getSimpleRef(o.get$ref()))); } cm.name = type; cm.classname = type; From 6d54799992ee7cd78d624f8bbb3299677d66c1af Mon Sep 17 00:00:00 2001 From: Alexej Date: Thu, 2 Apr 2020 22:06:56 +0200 Subject: [PATCH 14/16] Fix OpenAPITools#5381 fixed generation of oneOf models with descriminator --- .../openapitools/codegen/DefaultCodegen.java | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java index 71a5055a0e6e..73db3b3f488a 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java @@ -5769,28 +5769,30 @@ public void addOneOfNameExtension(ComposedSchema s, String name) { } /** - * Add a given ComposedSchema as an interface model to be generated + * Add a given ComposedSchema as an interface model to be generated, assuming it has `oneOf` defined * @param cs ComposedSchema object to create as interface model * @param type name to use for the generated interface model */ public void addOneOfInterfaceModel(ComposedSchema cs, String type) { + if (cs.getOneOf() == null) { + return; + } CodegenModel cm = new CodegenModel(); cm.discriminator = createDiscriminator("", (Schema) cs); - if (cs.getOneOf() != null){ - for (Schema o : cs.getOneOf()) { - if (o.get$ref() == null) { - if (cm.discriminator != null && o.get$ref() == null) { - // OpenAPI spec states that inline objects should not be considered when discriminator is used - // https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#discriminatorObject - LOGGER.warn("Ignoring inline object in oneOf definition of {}, since discriminator is used", type); - } else { - LOGGER.warn("Inline models are not supported in oneOf definition right now"); - } - continue; + + for (Schema o : cs.getOneOf()) { + if (o.get$ref() == null) { + if (cm.discriminator != null && o.get$ref() == null) { + // OpenAPI spec states that inline objects should not be considered when discriminator is used + // https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#discriminatorObject + LOGGER.warn("Ignoring inline object in oneOf definition of {}, since discriminator is used", type); + } else { + LOGGER.warn("Inline models are not supported in oneOf definition right now"); } - cm.oneOf.add(toModelName(ModelUtils.getSimpleRef(o.get$ref()))); + continue; } + cm.oneOf.add(toModelName(ModelUtils.getSimpleRef(o.get$ref()))); } cm.name = type; cm.classname = type; From 9b586fa9c03c1c7c914d5bed8f2380379f6a4931 Mon Sep 17 00:00:00 2001 From: Alexej Date: Wed, 3 Feb 2021 23:32:41 +0100 Subject: [PATCH 15/16] [Spring] codegen : oneOf support for spring (#5381) --- .../openapitools/codegen/DefaultCodegen.java | 71 ++++++++++++------- .../codegen/languages/SpringCodegen.java | 15 ++-- 2 files changed, 55 insertions(+), 31 deletions(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java index 1d30af652a84..dd7853493d51 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java @@ -805,11 +805,15 @@ public void preprocessOpenAPI(OpenAPI openAPI) { schemas.put(opId, requestSchema); } // process all response bodies - for (Map.Entry ar : op.getValue().getResponses().entrySet()) { - ApiResponse a = ModelUtils.getReferencedApiResponse(openAPI, ar.getValue()); - Schema responseSchema = ModelUtils.getSchemaFromResponse(a); - if (responseSchema != null) { - schemas.put(opId + ar.getKey(), responseSchema); + if (op.getValue().getResponses() != null) { + for (Map.Entry ar : op.getValue().getResponses() + .entrySet()) { + ApiResponse a = ModelUtils + .getReferencedApiResponse(openAPI, ar.getValue()); + Schema responseSchema = ModelUtils.getSchemaFromResponse(a); + if (responseSchema != null) { + schemas.put(opId + ar.getKey(), responseSchema); + } } } } @@ -832,26 +836,18 @@ public void preprocessOpenAPI(OpenAPI openAPI) { // go through all gathered schemas and add them as interfaces to be created for (Map.Entry e : schemas.entrySet()) { - String n = toModelName(e.getKey()); - Schema s = e.getValue(); - String nOneOf = toModelName(n + "OneOf"); - if (ModelUtils.isComposedSchema(s)) { - if (e.getKey().contains("/")) { - // if this is property schema, we also need to generate the oneOf interface model - addOneOfNameExtension((ComposedSchema) s, nOneOf); - addOneOfInterfaceModel((ComposedSchema) s, nOneOf, openAPI); - } else { - // else this is a component schema, so we will just use that as the oneOf interface model - addOneOfNameExtension((ComposedSchema) s, n); - } - } else if (ModelUtils.isArraySchema(s)) { - Schema items = ((ArraySchema) s).getItems(); + String modelName = toModelName(e.getKey()); + Schema schema = e.getValue(); + String nOneOf = toModelName(modelName + "OneOf"); + if (ModelUtils.isComposedSchema(schema)) { + addOneOfForComposedSchema(e, modelName, (ComposedSchema) schema, nOneOf, openAPI); + } else if (ModelUtils.isArraySchema(schema)) { + Schema items = ((ArraySchema) schema).getItems(); if (ModelUtils.isComposedSchema(items)) { - addOneOfNameExtension((ComposedSchema) items, nOneOf); - addOneOfInterfaceModel((ComposedSchema) items, nOneOf, openAPI); + addOneOfForComposedSchemaArray(nOneOf, openAPI, (ComposedSchema) items, modelName); } - } else if (ModelUtils.isMapSchema(s)) { - Schema addProps = getAdditionalProperties(s); + } else if (ModelUtils.isMapSchema(schema)) { + Schema addProps = ModelUtils.getAdditionalProperties(openAPI, schema); if (addProps != null && ModelUtils.isComposedSchema(addProps)) { addOneOfNameExtension((ComposedSchema) addProps, nOneOf); addOneOfInterfaceModel((ComposedSchema) addProps, nOneOf, openAPI); @@ -861,6 +857,25 @@ public void preprocessOpenAPI(OpenAPI openAPI) { } } + protected void addOneOfForComposedSchemaArray(String nOneOf, OpenAPI openAPI, + ComposedSchema items, String modelName) { + addOneOfNameExtension(items, nOneOf); + addOneOfInterfaceModel(items, nOneOf, openAPI); + } + + protected void addOneOfForComposedSchema(Entry stringSchemaEntry, + String modelName, ComposedSchema composedSchema, + String nOneOf, OpenAPI openAPI) { + if (stringSchemaEntry.getKey().contains("/")) { + // if this is property schema, we also need to generate the oneOf interface model + addOneOfNameExtension(composedSchema, nOneOf); + addOneOfInterfaceModel(composedSchema, nOneOf, openAPI); + } else { + // else this is a component schema, so we will just use that as the oneOf interface model + addOneOfNameExtension(composedSchema, modelName); + } + } + // override with any special handling of the entire OpenAPI spec document @SuppressWarnings("unused") public void processOpenAPI(OpenAPI openAPI) { @@ -5868,7 +5883,7 @@ protected void addBodyModelSchema(CodegenParameter codegenParameter, String name "'application/x-www-form-urlencoded' or 'multipart/?'"); LOGGER.warn("schema: " + schema); LOGGER.warn("codegenModel is null. Default to UNKNOWN_BASE_TYPE"); - codegenModelName = "UNKNOWN_BASE_TYPE"; + codegenModelName = getCodegenModelName(codegenProperty); codegenModelDescription = "UNKNOWN_DESCRIPTION"; } @@ -6113,6 +6128,14 @@ private void addJsonSchemaForBodyRequestInCaseItsNotPresent(CodegenParameter cod codegenParameter.jsonSchema = Json.pretty(body); } + protected void addAdditionalImports(Set imports, String complexType) { + imports.add(complexType); + } + + protected String getCodegenModelName(CodegenProperty codegenProperty) { + return "UNKNOWN_BASE_TYPE"; + } + protected void addOption(String key, String description, String defaultValue) { CliOption option = new CliOption(key, description); if (defaultValue != null) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java index 773a450ec96a..41248fbcc404 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java @@ -581,18 +581,19 @@ public void preprocessOpenAPI(OpenAPI openAPI) { } @Override - protected void addOneOfForComposedSchema(Entry stringSchemaEntry, String modelName, ComposedSchema composedSchema, - String nOneOf){ + protected void addOneOfForComposedSchema(Entry stringSchemaEntry, + String modelName, ComposedSchema composedSchema, + String nOneOf, OpenAPI openAPI) { // if this is property schema, we also need to generate the oneOf interface model addOneOfNameExtension(composedSchema, modelName); - addOneOfInterfaceModel(composedSchema, modelName); + addOneOfInterfaceModel(composedSchema, modelName, openAPI); } @Override - protected void addOneOfForComposedSchemaArray(String nOneOf, String modelName, - ComposedSchema items) { - addOneOfNameExtension(items, modelName); - addOneOfInterfaceModel(items, modelName); + protected void addOneOfForComposedSchemaArray(String nOneOf, OpenAPI openAPI, + ComposedSchema composedSchema, String modelName) { + addOneOfNameExtension(composedSchema, modelName); + addOneOfInterfaceModel(composedSchema, modelName, openAPI); } @Override From 15b362ade538cabcf840eafb3f088521270bb90f Mon Sep 17 00:00:00 2001 From: Alexej Date: Thu, 4 Feb 2021 21:39:20 +0100 Subject: [PATCH 16/16] [Spring] codegen : oneOf support for spring (#5381) avoid npe --- .../src/main/java/org/openapitools/codegen/DefaultCodegen.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java index dd7853493d51..25368227eb90 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java @@ -782,7 +782,7 @@ public void postProcessParameter(CodegenParameter parameter) { //override with any special handling of the entire OpenAPI spec document @SuppressWarnings("unused") public void preprocessOpenAPI(OpenAPI openAPI) { - if (useOneOfInterfaces) { + if (useOneOfInterfaces && openAPI.getComponents() != null) { // we process the openapi schema here to find oneOf schemas and create interface models for them Map schemas = new HashMap(openAPI.getComponents().getSchemas()); if (schemas == null) {