OpenAPITools / OpenAPITools/openapi-generator
[BUG] generator ignores format on objects
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 26.8k
- Forks
- 7.7k
- PR merge metrics
- PR metrics pending
Description
Bug Report Checklist
- Have you provided a full/minimal spec to reproduce the issue?
- Have you validated the input using an OpenAPI validator (example)?
- Have you tested with the latest master to confirm the issue still exists?
- Have you searched for related issues/PRs?
- What's the actual output vs expected output?
- [Optional] Sponsorship to speed up the bug fix or feature request (example)
Description
According to the JSON Schema Specification Draft 2020-12, valid instance data models are null, boolean, object, array, number, and string. Furthermore, according to the openapi specification, all OAS datatypes are based on the types supported by the aforementioned specification, and can have an optional modifier property: format. The JSON Schema Specification defines several formats for datatypes, as does the openapi specification.
The generator supports additional format options via importMappings and typeMappings. However, when a schema identified as a type: object is defined, the format is ignored by the validator.
When using a custom format for a custom object, it should be defined as a type: object. This way tools such as Postman can properly validate a schema against a response (it will fail on format as unknown format, however this can be ignored so long as it matches the type of object. However, defining as a type: string will always cause schema validation tools to fail because the received object is not of type: string.
openapi-generator version
6.2.1
OpenAPI declaration file content or url
openapi: 3.0.3
info:
title: My-API
version: 0.0.1
servers:
- url: 'https://localhost:8080'
paths:
/dates:
get:
operationId: getDates
responses:
"200":
$ref: '#/components/responses/DateResponse'
"5XX":
description: Unknown error has occured
summary: get dates
tags:
- Dates
components:
schemas:
DateCollection:
type: object
properties:
name:
type: string
objectDate:
type: object
format: instant
stringInstant:
type: string
format: instant
stringInstantRemappedDate:
type: string
format: date-time
responses:
DateResponse:
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/DateCollection'
-->
Generation Details
I am using the gradle plugin. Using the above yaml, I run the generator with these settings.
generatorName = "spring"
inputSpec = "$projectDir/src/main/resources/static/object-format-example.yml"
outputDir = "$projectDir"
apiPackage = "com.generated.api.spring"
invokerPackage = "com.generated.invoker.spring"
modelPackage = "com.generated.model.spring"
typeMappings = [
OffsetDateTime: "Instant",
instant: "Instant"
]
importMappings = [
Instant: "java.time.Instant"
]
configOptions = [
dateLibrary: "java8",
serializableModel: "true"
]
The resulting generated model from the above configuration looks like this
@JsonProperty("objectDate")
private Object objectDate;
@JsonProperty("stringInstant")
private Instant stringInstant;
@JsonProperty("stringInstantRemappedDate")
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
private Instant stringInstantRemappedDate;
Steps to reproduce
Step 1. Use the yaml above
Step 2. Use the mappings above
Step 3. generate models
Related issues/PRs
None that I could find
Suggest a fix
Line 808 of the InlineModelResolver explicitly sets the format of an object model. However, the format is only used if the type is type: string.
Suggest updating the DefaultCodegen.java to allow models with a defined format to be processed similarly to strings. Specifically, these lines should be updated to the following:
} else if (ModelUtils.isStringSchema(schema)) {
if (typeMapping.containsKey(schema.getFormat())) {
// If the format matches a typeMapping (supplied with the --typeMappings flag)
// then treat the format as a primitive type.
// This allows the typeMapping flag to add a new custom type which can then
// be used in the format field.
return schema.getFormat();
}
return "string";
} else if (isFreeFormObject(schema)) {
// Allows typeMapping flag to add a new custom type instead of an Object.
// By defining a format for an object, objects can pass most schema validators
// even if the format is unknown.
if (typeMapping.containsKey(schema.getFormat())) {
return schema.getFormat();
}
// Note: the value of a free-form object cannot be an arbitrary type. Per OAS specification,
// it must be a map of string to values.
return "object";
This would allow the schema to generate a custom object without defining a custom schema-mapping, and allow the schema to pass validation.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with InlineModelResolver.java around line 808 and DefaultCodegen.java around line 2364, then reproduce the Gradle generation using the YAML and typeMappings in the issue. Compare the generated DateCollection model with the expected custom type for objectDate, while preserving the existing string-format behavior; done means object formats can use typeMappings without a schema-mapping.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, openapi
- Domain
- backend-api-design, tooling
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 48/100