clone Schema using AnnotationUtils.clone with WA (to clone schemas wi… (#18867)

* clone Schema using AnnotationUtils.clone with WA (to clone schemas with example field set)

* changes after scripts run
This commit is contained in:
Nikita Shmakov 2024-06-06 15:55:51 +03:00 committed by GitHub
parent 6ae8a8f4c7
commit 3aba42733b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 50 additions and 32 deletions

View File

@ -2862,7 +2862,9 @@ public class DefaultCodegen implements CodegenConfig {
if (null != existingProperties && null != newProperties) { if (null != existingProperties && null != newProperties) {
Schema existingType = existingProperties.get("type"); Schema existingType = existingProperties.get("type");
Schema newType = newProperties.get("type"); Schema newType = newProperties.get("type");
newProperties.forEach((key, value) -> 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()) { if (null != existingType && null != newType && null != newType.getEnum() && !newType.getEnum().isEmpty()) {
for (Object e : newType.getEnum()) { for (Object e : newType.getEnum()) {
// ensure all interface enum types are added to schema // ensure all interface enum types are added to schema

View File

@ -17,10 +17,9 @@
package org.openapitools.codegen.utils; package org.openapitools.codegen.utils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; 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.OpenAPI;
import io.swagger.v3.oas.models.Operation; import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.PathItem; import io.swagger.v3.oas.models.PathItem;
@ -64,6 +63,8 @@ public class ModelUtils {
private static final String URI_FORMAT = "uri"; private static final String URI_FORMAT = "uri";
private static final Set<String> OPENAPI_TYPES = Set.of("array", "integer", "number", "boolean", "string", "object");
private static final String generateAliasAsModelKey = "generateAliasAsModel"; private static final String generateAliasAsModelKey = "generateAliasAsModel";
// A vendor extension to track the value of the 'swagger' field in a 2.0 doc, if applicable. // 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 JSON_MAPPER;
private static final ObjectMapper YAML_MAPPER; private static final ObjectMapper YAML_MAPPER;
private static final ObjectMapper TYPED_JSON_MAPPER = new ObjectMapper();
static { static {
JSON_MAPPER = ObjectMapperFactory.createJson(); JSON_MAPPER = ObjectMapperFactory.createJson();
YAML_MAPPER = ObjectMapperFactory.createYaml(); YAML_MAPPER = ObjectMapperFactory.createYaml();
BasicPolymorphicTypeValidator ptv = BasicPolymorphicTypeValidator.builder()
.allowIfSubType(Object.class)
.build();
TYPED_JSON_MAPPER.activateDefaultTyping(ptv, ObjectMapper.DefaultTyping.EVERYTHING);
} }
public static boolean isDisallowAdditionalPropertiesIfNotPresent() { public static boolean isDisallowAdditionalPropertiesIfNotPresent() {
@ -2186,13 +2181,19 @@ public class ModelUtils {
return false; return false;
} }
public static Schema cloneSchema(Schema schema) { public static Schema cloneSchema(Schema schema, boolean openapi31) {
try { if (openapi31) {
String json = TYPED_JSON_MAPPER.writeValueAsString(schema); return AnnotationsUtils.clone(schema, openapi31);
return TYPED_JSON_MAPPER.readValue(json, schema.getClass()); } else {
} catch (JsonProcessingException ex) { // AnnotationsUtils.clone doesn't support custom schema types for OpenAPI < 3.1
LOGGER.error("Can't clone schema {}", schema, ex); String schemaType = schema.getType();
return schema; if (schemaType != null && !OPENAPI_TYPES.contains(schemaType)) {
schema.setType(null);
}
Schema result = AnnotationsUtils.clone(schema, openapi31);
schema.setType(schemaType);
result.setType(schemaType);
return result;
} }
} }

View File

@ -399,26 +399,28 @@ public class ModelUtilsTest {
.name("test-schema") .name("test-schema")
.minimum(new BigDecimal(100)); .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 @Test
public void testCloneCustomSchema() { 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 @Test
public void testCloneComposedSchema() { public void testCloneComposedSchema() {
Schema base1 = new Schema() Schema base1 = new ObjectSchema()
.name("Base1") .name("Base1")
.addProperty("foo", new StringSchema()); .addProperty("foo", new StringSchema());
Schema base2 = new Schema() Schema base2 = new ObjectSchema()
.name("Base2") .name("Base2")
.addProperty("bar", new StringSchema()); .addProperty("bar", new StringSchema());
Schema composedSchema = new ComposedSchema() Schema composedSchema = new ComposedSchema()
@ -426,24 +428,37 @@ public class ModelUtilsTest {
.allOf(List.of(base1, base2)) .allOf(List.of(base1, base2))
.addProperty("baz", new StringSchema()); .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 @Test
public void testCloneArrayOfEnumsSchema() { public void testCloneArrayOfEnumsSchema() {
Schema arraySchema = new Schema() Schema schema = new ArraySchema()
.name("ArrayType") .name("ArrayType")
.type("array") .type("array")
.items(new Schema() .items(new StringSchema()
.type("string") .type("string")
._enum(List.of("SUCCESS", "FAILURE", "SKIPPED")) ._enum(List.of("SUCCESS", "FAILURE", "SKIPPED"))
) )
._default(List.of("SUCCESS", "FAILURE")); ._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);
} }
} }

View File

@ -30,13 +30,13 @@ DataQuery <- R6::R6Class(
#' Initialize a new DataQuery class. #' Initialize a new DataQuery class.
#' #'
#' @param id Query #' @param id Query
#' @param outcomes outcomes. Default to ["SUCCESS","FAILURE"]. #' @param outcomes outcomes. Default to [SUCCESS, FAILURE].
#' @param suffix test suffix #' @param suffix test suffix
#' @param text Some text containing white spaces #' @param text Some text containing white spaces
#' @param date A date #' @param date A date
#' @param ... Other optional arguments. #' @param ... Other optional arguments.
#' @export #' @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.null(`id`)) {
if (!(is.numeric(`id`) && length(`id`) == 1)) { if (!(is.numeric(`id`) && length(`id`) == 1)) {
stop(paste("Error! Invalid data for `id`. Must be an integer:", `id`)) stop(paste("Error! Invalid data for `id`. Must be an integer:", `id`))

View File

@ -5,7 +5,7 @@
Name | Type | Description | Notes Name | Type | Description | Notes
------------ | ------------- | ------------- | ------------- ------------ | ------------- | ------------- | -------------
**id** | **integer** | Query | [optional] **id** | **integer** | Query | [optional]
**outcomes** | **array[character]** | | [optional] [default to [&quot;SUCCESS&quot;,&quot;FAILURE&quot;]] [Enum: ] **outcomes** | **array[character]** | | [optional] [default to [SUCCESS, FAILURE]] [Enum: ]
**suffix** | **character** | test suffix | [optional] **suffix** | **character** | test suffix | [optional]
**text** | **character** | Some text containing white spaces | [optional] **text** | **character** | Some text containing white spaces | [optional]
**date** | **character** | A date | [optional] **date** | **character** | A date | [optional]