Remove restrictions for additional property types (#11802)

When a schema specifies additionalProperties: true, we need not restrict
those properties to a particular type. This change sets the schemas for
them to AnyType instead of object.

From a generation perspective, this only changes the output for
generators that differentiate between AnyType and object in their type
mappings; most do not. This fixes at least one bug in the Go and
TypeScript generators.
This commit is contained in:
Noah Fontes 2022-04-08 19:19:54 -07:00 committed by GitHub
parent e783e9b780
commit f6231d2488
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 60 additions and 15 deletions

View File

@ -1200,12 +1200,11 @@ public class ModelUtils {
*/
}
if (addProps == null || (addProps instanceof Boolean && (Boolean) addProps)) {
// Return ObjectSchema to specify any object (map) value is allowed.
// Set nullable to specify the value of additional properties may be
// the null value.
// Free-form additionalProperties don't need to have an inner
// additional properties, the type is already free-form.
return new ObjectSchema().additionalProperties(Boolean.FALSE).nullable(Boolean.TRUE);
// Return an empty schema as the properties can take on any type per
// the spec. See
// https://github.com/OpenAPITools/openapi-generator/issues/9282 for
// more details.
return new Schema();
}
return null;
}

View File

@ -5,7 +5,7 @@
*/
export interface {{classname}} {{#parent}}extends {{{.}}} {{/parent}}{
{{#additionalPropertiesType}}
[key: string]: {{{additionalPropertiesType}}}{{#hasVars}} | any{{/hasVars}};
[key: string]: {{{additionalPropertiesType}}}{{^additionalPropertiesIsAnyType}}{{#hasVars}} | any{{/hasVars}}{{/additionalPropertiesIsAnyType}};
{{/additionalPropertiesType}}
{{#vars}}

View File

@ -449,7 +449,7 @@ public class DefaultCodegenTest {
// extended with any undeclared properties.
Schema addProps = ModelUtils.getAdditionalProperties(openAPI, componentSchema);
Assert.assertNotNull(addProps);
Assert.assertTrue(addProps instanceof ObjectSchema);
Assert.assertEquals(addProps, new Schema());
CodegenModel cm = codegen.fromModel("AdditionalPropertiesClass", componentSchema);
Assert.assertNotNull(cm.getAdditionalProperties());
@ -494,7 +494,7 @@ public class DefaultCodegenTest {
Assert.assertNull(map_with_undeclared_properties_anytype_1_sc.getAdditionalProperties());
addProps = ModelUtils.getAdditionalProperties(openAPI, map_with_undeclared_properties_anytype_1_sc);
Assert.assertNotNull(addProps);
Assert.assertTrue(addProps instanceof ObjectSchema);
Assert.assertEquals(addProps, new Schema());
Assert.assertNotNull(map_with_undeclared_properties_anytype_1_cp.getAdditionalProperties());
// map_with_undeclared_properties_anytype_2
@ -504,7 +504,7 @@ public class DefaultCodegenTest {
Assert.assertNull(map_with_undeclared_properties_anytype_2_sc.getAdditionalProperties());
addProps = ModelUtils.getAdditionalProperties(openAPI, map_with_undeclared_properties_anytype_2_sc);
Assert.assertNotNull(addProps);
Assert.assertTrue(addProps instanceof ObjectSchema);
Assert.assertEquals(addProps, new Schema());
Assert.assertNotNull(map_with_undeclared_properties_anytype_2_cp.getAdditionalProperties());
// map_with_undeclared_properties_anytype_3
@ -517,7 +517,7 @@ public class DefaultCodegenTest {
Assert.assertEquals(map_with_undeclared_properties_anytype_3_sc.getAdditionalProperties(), Boolean.TRUE);
addProps = ModelUtils.getAdditionalProperties(openAPI, map_with_undeclared_properties_anytype_3_sc);
Assert.assertNotNull(addProps);
Assert.assertTrue(addProps instanceof ObjectSchema);
Assert.assertEquals(addProps, new Schema());
Assert.assertNotNull(map_with_undeclared_properties_anytype_3_cp.getAdditionalProperties());
// empty_map
@ -2769,6 +2769,26 @@ public class DefaultCodegenTest {
}
}
@Test
public void testAdditionalPropertiesAnyType() {
final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/issue_9282.yaml");
final DefaultCodegen codegen = new DefaultCodegen();
codegen.setOpenAPI(openAPI);
CodegenProperty anyTypeSchema = codegen.fromProperty("", new Schema());
Schema sc;
CodegenModel cm;
sc = openAPI.getComponents().getSchemas().get("AdditionalPropertiesTrue");
cm = codegen.fromModel("AdditionalPropertiesTrue", sc);
assertEquals(cm.getVars().get(0).additionalProperties, anyTypeSchema);
sc = openAPI.getComponents().getSchemas().get("AdditionalPropertiesAnyType");
cm = codegen.fromModel("AdditionalPropertiesAnyType", sc);
assertEquals(cm.getVars().get(0).additionalProperties, anyTypeSchema);
}
@Test
public void testIsXPresence() {
final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/issue_7651.yaml");

View File

@ -22,6 +22,7 @@ import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.media.ArraySchema;
import io.swagger.v3.oas.models.media.IntegerSchema;
import io.swagger.v3.oas.models.media.MapSchema;
import io.swagger.v3.oas.models.media.ObjectSchema;
import io.swagger.v3.oas.models.media.Schema;
import org.openapitools.codegen.CodegenConstants;
import org.openapitools.codegen.CodegenType;
@ -90,6 +91,13 @@ public class AbstractGoCodegenTest {
ModelUtils.setGenerateAliasAsModel(true);
defaultValue = codegen.getTypeDeclaration(schema);
Assert.assertEquals(defaultValue, "map[string]NestedArray");
// Create object schema with additionalProperties set to true
schema = new ObjectSchema().additionalProperties(Boolean.TRUE);
ModelUtils.setGenerateAliasAsModel(false);
defaultValue = codegen.getTypeDeclaration(schema);
Assert.assertEquals(defaultValue, "map[string]interface{}");
}
private static class P_AbstractGoCodegen extends AbstractGoCodegen {

View File

@ -0,0 +1,18 @@
openapi: 3.0.0
components:
schemas:
AdditionalPropertiesTrue:
description: additionalProperties set to true
type: object
properties:
child:
type: object
additionalProperties: true
AdditionalPropertiesAnyType:
description: additionalProperties set to any type explicitly
type: object
properties:
child:
type: object
additionalProperties: {}

View File

@ -59,10 +59,10 @@ export interface AdditionalPropertiesClass {
'map_with_undeclared_properties_anytype_2'?: object;
/**
*
* @type {{ [key: string]: object; }}
* @type {{ [key: string]: any; }}
* @memberof AdditionalPropertiesClass
*/
'map_with_undeclared_properties_anytype_3'?: { [key: string]: object; };
'map_with_undeclared_properties_anytype_3'?: { [key: string]: any; };
/**
* an object with no declared properties and no undeclared properties, hence it\'s an empty map.
* @type {object}
@ -1706,7 +1706,7 @@ export interface Whale {
* @interface Zebra
*/
export interface Zebra {
[key: string]: object | any;
[key: string]: any;
/**
*

View File

@ -173,7 +173,7 @@ export interface ArrayTest {
* @interface Banana
*/
export interface Banana {
[key: string]: object | any;
[key: string]: any;
/**
*