Reputation: 21122
I am working on an application which uses the springdoc-openapi library to generate OpenAPI v3 endpoints for its Spring controllers. This library uses Swagger Core for the actual mapping of Java Objects to OpenAPI schemas.
There is a request/response type used by a controller which includes a property of type Object
.
public class TypeWithObject {
private Object value;
public Object getValue() { return value; }
public void setValue(Object value) { this.value = value; }
}
This type can therefore be any of the data types defined by OpenAPI: string
, number
, integer
, boolean
, array
, or object
. Note that object
is a distinct type from the other types; e.g. a string
or boolean
is not an object
.
The OpenAPI 3.0 Specification specifies that a schema without any type will match any data type.
A schema without a type matches any data type – numbers, strings, objects, and so on.
A proper way to model this, then, would be the following Swagger definition, where there is no type
property for value
:
{
"openapi": "3.0.1",
"info": {
"title": "OpenAPI definition",
"version": "v0"
},
"components": {
"schemas": {
"TypeWithObject": {
"type": "object",
"properties": {
"value": {}
}
}
}
}
}
However, per open issue swagger-core#3834, Java Object
values are mapped to OpenAPI object
types, not an arbitrary type. As noted above, this means that it would be incorrect for such an API to return or accept a type that is not an OpenAPI object
, such as a string
, number
, boolean
, etc.
I made various attempts to get the application to generate this type as the OpenAPI arbitrary type, but to no avail. One thing I discovered when playing around with using a custom ModelConverter
to use a Swagger Schema
with a null type
is that Swagger Core
ends up converting the type to object
as part of its internal processing. This is currently documented as an open feature request of Swagger Core as swagger-core#4014.
With this all being said: how can I get my generated type to use the OpenAPI arbitrary type?
Upvotes: 3
Views: 1795
Reputation: 21122
One approach is to manually define an arbitrary type schema in a separate file, and use the OpenAPI $ref
keyword (applied using @Schema(ref="...")
) to reference this type.
api-docs-anyvalue.yml
:
components:
schemas:
AnyValue: {}
import io.swagger.v3.oas.annotations.media.Schema;
public class TypeWithObject {
@Schema(ref = "api-docs-anyvalue.yml#/components/schemas/AnyValue")
private Object value;
public Object getValue() { return value; }
public void setValue(Object value) { this.value = value; }
}
Result:
{
"openapi": "3.0.1",
"info": {
"title": "OpenAPI definition",
"version": "v0"
},
"components": {
"schemas": {
"TypeWithObject": {
"type": "object",
"properties": {
"value": {
"$ref": "api-docs-anyvalue.yml#/components/schemas/AnyValue"
}
}
}
}
}
}
Upvotes: 2