Skip to content

Commit ee957ed

Browse files
committed
Add support for additional use cases of free-form objects
Issue OpenAPITools#5969 and PR OpenAPITools#5970 document an issue with rust-server where free form models are not generated. OpenAPITools#7373 adds some free form model generation to python-experimental (later ported to other languages, it seems), but this feature only covers two of three possible use cases. The third use case remains unimplemented, though it is used in some larger OpenAPI document sets, such as DMTF's Redfish schema (which contains 33 of these free form objects without validation). related functions), but there does not seem to be an adequate replacement for detecting free form objects in the OpenAPI data model from template context. Unfortunately, free form objects require special consideration in statically type-checked languages such as Rust. quickly closed, presumably because `isFreeFormObject` was still present in the data model at the time the issue was opened. This commit adds a global property (default `false`) called `generateFreeFormModels` (I'm taking suggestions for a better name) which enables generation for the third use case not addressed by OpenAPITools#7373. Additionally, isFreeFormObject is added back into the object model for any case where a free-form object is generated, allowing generators for languages such as Rust to handle them gracefully.
1 parent ccbea26 commit ee957ed

File tree

4 files changed

+18
-6
lines changed

4 files changed

+18
-6
lines changed

modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenConstants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public class CodegenConstants {
3333

3434
public static final String WITH_XML = "withXml";
3535
public static final String SKIP_FORM_MODEL = "skipFormModel";
36+
public static final String GENERATE_FREE_FORM_MODELS = "generateUnaliasedFreeFormModels";
3637
/* /end System Properties */
3738

3839
public static final String API_NAME = "apiName";

modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenModel.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public class CodegenModel implements IJsonSchemaValidationProperties {
6666
public String defaultValue;
6767
public String arrayModelType;
6868
public boolean isAlias; // Is this effectively an alias of another simple type
69-
public boolean isString, isInteger, isLong, isNumber, isNumeric, isFloat, isDouble, isDate, isDateTime, isDecimal, isShort, isUnboundedInteger, isPrimitiveType, isBoolean;
69+
public boolean isString, isInteger, isLong, isNumber, isNumeric, isFloat, isDouble, isDate, isDateTime, isDecimal, isShort, isUnboundedInteger, isPrimitiveType, isBoolean, isFreeFormObject;
7070
private boolean additionalPropertiesIsAnyType;
7171
public List<CodegenProperty> vars = new ArrayList<>(); // all properties (without parent's properties)
7272
public List<CodegenProperty> allVars = new ArrayList<>(); // all properties (with parent's properties)
@@ -949,6 +949,10 @@ public void setIsAnyType(boolean isAnyType) {
949949
this.isAnyType = isAnyType;
950950
}
951951

952+
public boolean getIsFreeFormObject() { return isFreeFormObject; }
953+
954+
public void setIsFreeFormObject(boolean isFreeFormObject) { this.isFreeFormObject = isFreeFormObject; }
955+
952956
public boolean getIsUuid() { return isUuid; }
953957

954958
public void setIsUuid(boolean isUuid) { this.isUuid = isUuid; }
@@ -1096,7 +1100,7 @@ hasChildren, isMap, isDeprecated, hasOnlyReadOnly, getExternalDocumentation(), g
10961100
getMinItems(), getMaxLength(), getMinLength(), getExclusiveMinimum(), getExclusiveMaximum(), getMinimum(),
10971101
getMaximum(), getPattern(), getMultipleOf(), getItems(), getAdditionalProperties(), getIsModel(),
10981102
getAdditionalPropertiesIsAnyType(), hasDiscriminatorWithNonEmptyMapping,
1099-
isAnyType, getComposedSchemas(), hasMultipleTypes, isDecimal, isUuid, requiredVarsMap, ref,
1103+
isAnyType, isFreeFormObject, getComposedSchemas(), hasMultipleTypes, isDecimal, isUuid, requiredVarsMap, ref,
11001104
uniqueItemsBoolean, schemaIsFromAdditionalProperties, isBooleanSchemaTrue, isBooleanSchemaFalse,
11011105
format, dependentRequired, contains);
11021106
}

modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2788,6 +2788,7 @@ protected void updateModelForObject(CodegenModel m, Schema schema) {
27882788
// non-composed object type with no properties + additionalProperties
27892789
// additionalProperties must be null, ObjectSchema, or empty Schema
27902790
addAdditionPropertiesToCodeGenModel(m, schema);
2791+
m.setIsFreeFormObject(true);
27912792
}
27922793
// process 'additionalProperties'
27932794
setAddProps(schema, m);
@@ -7002,6 +7003,7 @@ protected void updateRequestBodyForMap(CodegenParameter codegenParameter, Schema
70027003
codegenParameter.isContainer = Boolean.TRUE;
70037004
codegenParameter.isMap = Boolean.TRUE;
70047005
codegenParameter.isNullable = codegenProperty.isNullable;
7006+
codegenParameter.isFreeFormObject = codegenProperty.isFreeFormObject;
70057007

70067008
// set nullable
70077009
setParameterNullable(codegenParameter, codegenProperty);

modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultGenerator.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -489,13 +489,18 @@ void generateModels(List<File> files, List<ModelMap> allModels, List<String> unu
489489
// 2. free form with validation
490490
// 3. free form that is allOf included in any composed schemas
491491
// this use case arises when using interface schemas
492-
// generators may choose to make models for use case 2 + 3
492+
// Use cases 2 + 3 are enabled by default, but use case 1 is hidden behind global property
493+
// generateFreeFormModels.
493494
Schema refSchema = new Schema();
494495
refSchema.set$ref("#/components/schemas/" + name);
495496
Schema unaliasedSchema = config.unaliasSchema(refSchema);
496-
if (unaliasedSchema.get$ref() == null) {
497-
LOGGER.info("Model {} not generated since it's a free-form object", name);
498-
continue;
497+
498+
Boolean generateFreeFormModels = GlobalSettings.getProperty(CodegenConstants.GENERATE_FREE_FORM_MODELS) != null ?
499+
Boolean.valueOf(GlobalSettings.getProperty(CodegenConstants.GENERATE_FREE_FORM_MODELS)) :
500+
getGeneratorPropertyDefaultSwitch(CodegenConstants.GENERATE_FREE_FORM_MODELS, false);
501+
if (unaliasedSchema.get$ref() == null && !generateFreeFormModels) {
502+
LOGGER.info("Model {} not generated since it's a free-form object. To enable this, set generateFreeFormModels=true", name);
503+
continue;
499504
}
500505
} else if (ModelUtils.isMapSchema(schema)) { // check to see if it's a "map" model
501506
// A composed schema (allOf, oneOf, anyOf) is considered a Map schema if the additionalproperties attribute is set

0 commit comments

Comments
 (0)