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 8e2d9d8a8327..2954b06c8d8e 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 @@ -2862,7 +2862,9 @@ private void mergeProperties(Map existingProperties, Map existingProperties.put(key, ModelUtils.cloneSchema(value))); + newProperties.forEach((key, value) -> + existingProperties.put(key, ModelUtils.cloneSchema(value, specVersionGreaterThanOrEqualTo310(openAPI))) + ); if (null != existingType && null != newType && null != newType.getEnum() && !newType.getEnum().isEmpty()) { for (Object e : newType.getEnum()) { // ensure all interface enum types are added to schema diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/ModelUtils.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/ModelUtils.java index fc25c6ff0d93..966dbaebd5ca 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/ModelUtils.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/ModelUtils.java @@ -17,10 +17,9 @@ package org.openapitools.codegen.utils; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.jsontype.BasicPolymorphicTypeValidator; +import io.swagger.v3.core.util.AnnotationsUtils; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.Operation; import io.swagger.v3.oas.models.PathItem; @@ -64,6 +63,8 @@ public class ModelUtils { private static final String URI_FORMAT = "uri"; + private static final Set OPENAPI_TYPES = Set.of("array", "integer", "number", "boolean", "string", "object"); + private static final String generateAliasAsModelKey = "generateAliasAsModel"; // A vendor extension to track the value of the 'swagger' field in a 2.0 doc, if applicable. @@ -76,16 +77,10 @@ public class ModelUtils { private static final ObjectMapper JSON_MAPPER; private static final ObjectMapper YAML_MAPPER; - private static final ObjectMapper TYPED_JSON_MAPPER = new ObjectMapper(); static { JSON_MAPPER = ObjectMapperFactory.createJson(); YAML_MAPPER = ObjectMapperFactory.createYaml(); - - BasicPolymorphicTypeValidator ptv = BasicPolymorphicTypeValidator.builder() - .allowIfSubType(Object.class) - .build(); - TYPED_JSON_MAPPER.activateDefaultTyping(ptv, ObjectMapper.DefaultTyping.EVERYTHING); } public static boolean isDisallowAdditionalPropertiesIfNotPresent() { @@ -2186,13 +2181,19 @@ public static boolean isParent(Schema schema) { return false; } - public static Schema cloneSchema(Schema schema) { - try { - String json = TYPED_JSON_MAPPER.writeValueAsString(schema); - return TYPED_JSON_MAPPER.readValue(json, schema.getClass()); - } catch (JsonProcessingException ex) { - LOGGER.error("Can't clone schema {}", schema, ex); - return schema; + public static Schema cloneSchema(Schema schema, boolean openapi31) { + if (openapi31) { + return AnnotationsUtils.clone(schema, openapi31); + } else { + // AnnotationsUtils.clone doesn't support custom schema types for OpenAPI < 3.1 + String schemaType = schema.getType(); + if (schemaType != null && !OPENAPI_TYPES.contains(schemaType)) { + schema.setType(null); + } + Schema result = AnnotationsUtils.clone(schema, openapi31); + schema.setType(schemaType); + result.setType(schemaType); + return result; } } diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/utils/ModelUtilsTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/utils/ModelUtilsTest.java index 187e22f55cc8..067bd3b1dcd1 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/utils/ModelUtilsTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/utils/ModelUtilsTest.java @@ -399,26 +399,28 @@ public void testCloneNumberSchema() { .name("test-schema") .minimum(new BigDecimal(100)); - Schema deepCopy = ModelUtils.cloneSchema(schema); + Schema deepCopy = ModelUtils.cloneSchema(schema, false); - Assert.assertEquals(schema, deepCopy); + Assert.assertEquals(deepCopy, schema); + Assert.assertNotSame(deepCopy, schema); } @Test public void testCloneCustomSchema() { - Schema schema = new Schema().type("money"); + Schema schema = new ObjectSchema().type("money"); - Schema deepCopy = ModelUtils.cloneSchema(schema); + Schema deepCopy = ModelUtils.cloneSchema(schema, false); - Assert.assertEquals(schema, deepCopy); + Assert.assertEquals(deepCopy, schema); + Assert.assertNotSame(deepCopy, schema); } @Test public void testCloneComposedSchema() { - Schema base1 = new Schema() + Schema base1 = new ObjectSchema() .name("Base1") .addProperty("foo", new StringSchema()); - Schema base2 = new Schema() + Schema base2 = new ObjectSchema() .name("Base2") .addProperty("bar", new StringSchema()); Schema composedSchema = new ComposedSchema() @@ -426,24 +428,37 @@ public void testCloneComposedSchema() { .allOf(List.of(base1, base2)) .addProperty("baz", new StringSchema()); - var deepCopy = ModelUtils.cloneSchema(composedSchema); + Schema deepCopy = ModelUtils.cloneSchema(composedSchema, false); - Assert.assertEquals(composedSchema, deepCopy); + Assert.assertEquals(deepCopy, composedSchema); + Assert.assertNotSame(deepCopy, composedSchema); } @Test public void testCloneArrayOfEnumsSchema() { - Schema arraySchema = new Schema() + Schema schema = new ArraySchema() .name("ArrayType") .type("array") - .items(new Schema() + .items(new StringSchema() .type("string") ._enum(List.of("SUCCESS", "FAILURE", "SKIPPED")) ) ._default(List.of("SUCCESS", "FAILURE")); - var deepCopy = ModelUtils.cloneSchema(arraySchema); + Schema deepCopy = ModelUtils.cloneSchema(schema, false); - Assert.assertEquals(arraySchema, deepCopy); + Assert.assertEquals(deepCopy, schema); + Assert.assertNotSame(deepCopy, schema); + } + + @Test + public void testCloneDateTimeSchemaWithExample() { + Schema schema = new DateTimeSchema() + .example("2020-02-02T20:20:20.000222Z"); + + Schema deepCopy = ModelUtils.cloneSchema(schema, false); + + Assert.assertEquals(deepCopy, schema); + Assert.assertNotSame(deepCopy, schema); } } diff --git a/samples/client/echo_api/r/R/data_query.R b/samples/client/echo_api/r/R/data_query.R index 228cd65b8467..0a749f98d6ed 100644 --- a/samples/client/echo_api/r/R/data_query.R +++ b/samples/client/echo_api/r/R/data_query.R @@ -30,13 +30,13 @@ DataQuery <- R6::R6Class( #' Initialize a new DataQuery class. #' #' @param id Query - #' @param outcomes outcomes. Default to ["SUCCESS","FAILURE"]. + #' @param outcomes outcomes. Default to [SUCCESS, FAILURE]. #' @param suffix test suffix #' @param text Some text containing white spaces #' @param date A date #' @param ... Other optional arguments. #' @export - initialize = function(`id` = NULL, `outcomes` = ["SUCCESS","FAILURE"], `suffix` = NULL, `text` = NULL, `date` = NULL, ...) { + initialize = function(`id` = NULL, `outcomes` = [SUCCESS, FAILURE], `suffix` = NULL, `text` = NULL, `date` = NULL, ...) { if (!is.null(`id`)) { if (!(is.numeric(`id`) && length(`id`) == 1)) { stop(paste("Error! Invalid data for `id`. Must be an integer:", `id`)) diff --git a/samples/client/echo_api/r/docs/DataQuery.md b/samples/client/echo_api/r/docs/DataQuery.md index 50015244dc5b..097f1885fe5f 100644 --- a/samples/client/echo_api/r/docs/DataQuery.md +++ b/samples/client/echo_api/r/docs/DataQuery.md @@ -5,7 +5,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **id** | **integer** | Query | [optional] -**outcomes** | **array[character]** | | [optional] [default to ["SUCCESS","FAILURE"]] [Enum: ] +**outcomes** | **array[character]** | | [optional] [default to [SUCCESS, FAILURE]] [Enum: ] **suffix** | **character** | test suffix | [optional] **text** | **character** | Some text containing white spaces | [optional] **date** | **character** | A date | [optional]