better support of allOf with 1 sub-schema (#14882)

This commit is contained in:
William Cheng 2023-03-07 00:35:34 +08:00 committed by GitHub
parent d497c3d087
commit 70faa6b15c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 152 additions and 4 deletions

View File

@ -3764,6 +3764,18 @@ public class DefaultCodegen implements CodegenConfig {
return cpc;
}
Schema original = null;
// check if it's allOf (only 1 sub schema) with default/nullable/etc set in the top level
if (ModelUtils.isAllOf(p) && p.getAllOf().size() == 1 && ModelUtils.hasCommonAttributesDefined(p) ) {
if (p.getAllOf().get(0) instanceof Schema) {
original = p;
p = (Schema) p.getAllOf().get(0);
} else {
LOGGER.error("Unknown type in allOf schema. Please report the issue via openapi-generator's Github issue tracker.");
}
}
CodegenProperty property = CodegenModelFactory.newInstance(CodegenModelType.PROPERTY);
if (p.equals(trueSchema)) {
property.setIsBooleanSchemaTrue(true);
@ -3957,6 +3969,25 @@ public class DefaultCodegen implements CodegenConfig {
property.isModel = (ModelUtils.isComposedSchema(referencedSchema) || ModelUtils.isObjectSchema(referencedSchema)) && ModelUtils.isModel(referencedSchema);
}
// restore original schema with default value, nullable, readonly etc
if (original != null) {
p = original;
// evaluate common attributes defined in the top level
if (p.getNullable() != null) {
property.isNullable = p.getNullable();
} else if (p.getExtensions() != null && p.getExtensions().containsKey("x-nullable")) {
property.isNullable = (Boolean) p.getExtensions().get("x-nullable");
}
if (p.getReadOnly() != null) {
property.isReadOnly = p.getReadOnly();
}
if (p.getWriteOnly() != null) {
property.isWriteOnly = p.getWriteOnly();
}
}
// set the default value
property.defaultValue = toDefaultValue(property, p);
property.defaultValueWithParam = toDefaultValueWithParam(name, p);

View File

@ -1852,4 +1852,55 @@ public class ModelUtils {
return new SemVer(version);
}
/**
* Returns true if the schema contains allOf but
* no properties/oneOf/anyOf defined.
*
* @param schema the schema
* @return true if the schema contains allOf but no properties/oneOf/anyOf defined.
*/
public static boolean isAllOf(Schema schema) {
if (hasAllOf(schema) && (schema.getProperties() == null || schema.getProperties().isEmpty()) &&
(schema.getOneOf() == null || schema.getOneOf().isEmpty()) &&
(schema.getAnyOf() == null || schema.getAnyOf().isEmpty())) {
return true;
}
return false;
}
/**
* Returns true if the schema contains allOf and may or may not have
* properties/oneOf/anyOf defined.
*
* @param schema the schema
* @return true if allOf is not empty
*/
public static boolean hasAllOf(Schema schema) {
if (schema.getAllOf() != null && !schema.getAllOf().isEmpty()) {
return true;
}
return false;
}
/**
* Returns true if any of the common attributes of the schema (e.g. readOnly, default, maximum, etc) is defined.
*
* @param schema the schema
* @return true if allOf is not empty
*/
public static boolean hasCommonAttributesDefined(Schema schema) {
if (schema.getNullable() != null || schema.getDefault() != null ||
schema.getMinimum() != null || schema.getMinimum() != null ||
schema.getExclusiveMaximum() != null || schema.getExclusiveMinimum() != null ||
schema.getMinLength() != null || schema.getMaxLength() != null ||
schema.getMinItems() != null || schema.getMaxItems() != null ||
schema.getReadOnly() != null || schema.getWriteOnly() != null) {
return true;
}
return false;
}
}

View File

@ -4294,6 +4294,31 @@ public class DefaultCodegenTest {
Assert.assertFalse(referencedEnumSchemaProperty.isPrimitiveType);
}
@Test
public void testAllOfDefaultEnumType() {
// test allOf with a single sub-schema and default value set in the top level
final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/issue-5676-enums.yaml");
final DefaultCodegen codegen = new DefaultCodegen();
codegen.setOpenAPI(openAPI);
String modelName = "EnumPatternObject";
Schema schemaWithReferencedEnum = openAPI.getComponents().getSchemas().get(modelName);
CodegenModel modelWithReferencedSchema = codegen.fromModel(modelName, schemaWithReferencedEnum);
CodegenProperty defaultEnumSchemaProperty = modelWithReferencedSchema.vars.get(4);
Assert.assertNotNull(schemaWithReferencedEnum);
Assert.assertTrue(modelWithReferencedSchema.hasEnums);
Assert.assertEquals(defaultEnumSchemaProperty.getName(), "defaultMinusnumberMinusenum");
Assert.assertFalse(defaultEnumSchemaProperty.isEnum);
Assert.assertTrue(defaultEnumSchemaProperty.getIsEnumOrRef());
Assert.assertTrue(defaultEnumSchemaProperty.isEnumRef);
Assert.assertFalse(defaultEnumSchemaProperty.isInnerEnum);
Assert.assertFalse(defaultEnumSchemaProperty.isString);
Assert.assertFalse(defaultEnumSchemaProperty.isContainer);
Assert.assertFalse(defaultEnumSchemaProperty.isPrimitiveType);
Assert.assertEquals(defaultEnumSchemaProperty.defaultValue, "2");
}
@Test
public void testInlineEnumType() {
final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/issue-5676-enums.yaml");

View File

@ -211,3 +211,8 @@ components:
nullable: true
allOf:
- $ref: "#/components/schemas/NumberEnum"
default-number-enum:
default: 2
allOf:
- $ref: "#/components/schemas/NumberEnum"

View File

@ -33,9 +33,9 @@ import {
export interface FakeEnumRequestGetInlineRequest {
stringEnum?: FakeEnumRequestGetInlineStringEnumEnum;
nullableStringEnum?: string | null;
nullableStringEnum?: FakeEnumRequestGetInlineNullableStringEnumEnum;
numberEnum?: FakeEnumRequestGetInlineNumberEnumEnum;
nullableNumberEnum?: number | null;
nullableNumberEnum?: FakeEnumRequestGetInlineNullableNumberEnumEnum;
}
export interface FakeEnumRequestGetRefRequest {
@ -203,6 +203,15 @@ export const FakeEnumRequestGetInlineStringEnumEnum = {
Three: 'three'
} as const;
export type FakeEnumRequestGetInlineStringEnumEnum = typeof FakeEnumRequestGetInlineStringEnumEnum[keyof typeof FakeEnumRequestGetInlineStringEnumEnum];
/**
* @export
*/
export const FakeEnumRequestGetInlineNullableStringEnumEnum = {
One: 'one',
Two: 'two',
Three: 'three'
} as const;
export type FakeEnumRequestGetInlineNullableStringEnumEnum = typeof FakeEnumRequestGetInlineNullableStringEnumEnum[keyof typeof FakeEnumRequestGetInlineNullableStringEnumEnum];
/**
* @export
*/
@ -212,3 +221,12 @@ export const FakeEnumRequestGetInlineNumberEnumEnum = {
NUMBER_3: 3
} as const;
export type FakeEnumRequestGetInlineNumberEnumEnum = typeof FakeEnumRequestGetInlineNumberEnumEnum[keyof typeof FakeEnumRequestGetInlineNumberEnumEnum];
/**
* @export
*/
export const FakeEnumRequestGetInlineNullableNumberEnumEnum = {
NUMBER_1: 1,
NUMBER_2: 2,
NUMBER_3: 3
} as const;
export type FakeEnumRequestGetInlineNullableNumberEnumEnum = typeof FakeEnumRequestGetInlineNullableNumberEnumEnum[keyof typeof FakeEnumRequestGetInlineNullableNumberEnumEnum];

View File

@ -33,9 +33,9 @@ import {
export interface FakeEnumRequestGetInlineRequest {
stringEnum?: FakeEnumRequestGetInlineStringEnumEnum;
nullableStringEnum?: string | null;
nullableStringEnum?: FakeEnumRequestGetInlineNullableStringEnumEnum;
numberEnum?: FakeEnumRequestGetInlineNumberEnumEnum;
nullableNumberEnum?: number | null;
nullableNumberEnum?: FakeEnumRequestGetInlineNullableNumberEnumEnum;
}
export interface FakeEnumRequestGetRefRequest {
@ -203,6 +203,15 @@ export enum FakeEnumRequestGetInlineStringEnumEnum {
Two = 'two',
Three = 'three'
}
/**
* @export
* @enum {string}
*/
export enum FakeEnumRequestGetInlineNullableStringEnumEnum {
One = 'one',
Two = 'two',
Three = 'three'
}
/**
* @export
* @enum {string}
@ -212,3 +221,12 @@ export enum FakeEnumRequestGetInlineNumberEnumEnum {
NUMBER_2 = 2,
NUMBER_3 = 3
}
/**
* @export
* @enum {string}
*/
export enum FakeEnumRequestGetInlineNullableNumberEnumEnum {
NUMBER_1 = 1,
NUMBER_2 = 2,
NUMBER_3 = 3
}