M. Justin
M. Justin

Reputation: 21122

How can I generate the OpenAPI arbitrary type using Swagger Core (springdoc-openapi)?

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

Answers (1)

M. Justin
M. Justin

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

Related Questions