Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Codegen] Convert "any type" to oneOf model #6051

Next Next commit
Early draft to handle conversion from any type to oneOf schema
  • Loading branch information
sebastien-rosset committed Apr 25, 2020
commit 0c3f4793c8feb319c96d0c61ec93b445d509d754
Original file line number Diff line number Diff line change
Expand Up @@ -1886,7 +1886,9 @@ public String toOneOfName(List<String> names, ComposedSchema composedSchema) {
*/
private String getSingleSchemaType(Schema schema) {
Schema unaliasSchema = ModelUtils.unaliasSchema(this.openAPI, schema, importMapping);

if (unaliasSchema == null) {
throw new RuntimeException("Schema '" + schema.getName() + "' is invalid");
}
if (StringUtils.isNotBlank(unaliasSchema.get$ref())) { // reference to another definition/schema
// get the schema/model name from $ref
String schemaName = ModelUtils.getSimpleRef(unaliasSchema.get$ref());
Expand Down Expand Up @@ -2100,6 +2102,33 @@ public String toModelName(final String name) {
return camelize(modelNamePrefix + "_" + name + "_" + modelNameSuffix);
}

// Returns a model that encapsulates the JSON schema "any type". Its value
// can be one of null, integer, boolean, number, string, array or map.
// "Any type" is a schema that does not have the "type" attribute
// specified in the OpenAPI schema. That means the value can be any valid
// payload, i.e. the null value, boolean, string, integer, number,
// array or map.
// Map any schema to a 'oneOf' composed schema that has all possible types.
public CodegenModel getAnyTypeModel(String name, Schema schema) {
if (!ModelUtils.isAnyTypeSchema(schema)) {
throw new RuntimeException("Schema '" + name + "' is not 'any type'");
}
ComposedSchema s = (ComposedSchema) new ComposedSchema()
.addOneOfItem(new ObjectSchema().type("null"))
.addOneOfItem(new BooleanSchema())
.addOneOfItem(new StringSchema())
.addOneOfItem(new IntegerSchema())
.addOneOfItem(new NumberSchema())
.addOneOfItem(new ArraySchema())
.addOneOfItem(new MapSchema())
.name(name);
if (schema != null) {
s.setTitle(schema.getTitle());
s.setDescription(schema.getDescription());
}
return fromModel(name, s);
}

/**
* Convert OAS Model object to Codegen Model object
*
Expand All @@ -2121,6 +2150,11 @@ public CodegenModel fromModel(String name, Schema schema) {
return null;
}

if (ModelUtils.isAnyTypeSchema(schema)) {
LOGGER.warn("Schema is any type: {}", name);
return getAnyTypeModel(name, schema);
}
Copy link
Contributor

@spacether spacether Apr 28, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code only covers the case when the user include AnyType as a model schema.
Below I see that you you also handle the Model property case, but that code does not create a schema/model that the property can refer to.

What if we have AnyTypeSchema in:

  • a Model property
  • a Model
  • Inline in a response definition?

For example if AnyType is only in a model property AND/or an inline response definition there is no Model/Schema that it should be $ref connected to. In my opinion, we should make this model so it can be handled by all generators.

How about instead in the InlineModelResolver

  • pre-processing the the openapi document to check for the locations that need to be fixed
  • then insert qty 1 anyTypeModel into the openapi document
AnyType:
  anyOf:
  - type: "null"
  - type: integer
  - type: array ...
  • link all references that require it to that $ref
    Then we don't need any specific logic like you are adding in python-experimental.


CodegenModel m = CodegenModelFactory.newInstance(CodegenModelType.MODEL);

if (reservedWords.contains(name)) {
Expand Down Expand Up @@ -2155,7 +2189,6 @@ public CodegenModel fromModel(String name, Schema schema) {
m.xmlNamespace = schema.getXml().getNamespace();
m.xmlName = schema.getXml().getName();
}

if (ModelUtils.isArraySchema(schema)) {
m.isArrayModel = true;
m.arrayModelType = fromProperty(name, schema).complexType;
Expand Down