I have a sample SpringBoot API with the following features:
I try to generate an OpenApi contract from this API with springdoc-openapi-maven-plugin.
In my pom.xml, I have the following elements:
Here are my classes I generate schema from.
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
public class ContainerClass {
@ArraySchema(
arraySchema = @Schema(discriminatorProperty = "classType"),
schema = @Schema(implementation = ParentClass.class)
)
public List<ParentClass> elements;
// + Getter/Setter
}
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.EXISTING_PROPERTY,
property = "classType",
defaultImpl = ParentClass.class,
visible = true)
@JsonSubTypes({
@JsonSubTypes.Type(value = ChildA.class, name = "CHILD_A"),
@JsonSubTypes.Type(value = ChildB.class, name = "CHILD_B")})
@Schema(
description = "Parent description",
discriminatorProperty = "classType",
discriminatorMapping = {
@DiscriminatorMapping(value = "CHILD_A", schema = ChildA.class),
@DiscriminatorMapping(value = "CHILD_B", schema = ChildB.class)
}
)
public abstract class ParentClass {
public String classType;
// + Getter/Setter
}
@io.swagger.v3.oas.annotations.media.Schema(description = " Child A", allOf = ParentClass.class)
public class ChildA extends ParentClass{
}
@io.swagger.v3.oas.annotations.media.Schema(description = " Child B", allOf = ParentClass.class)
public class ChildB extends ParentClass{
}
When I run springdoc-openapi-maven-plugin, I get the following contract file.
openapi: 3.0.1
info:
title: OpenAPI definition
version: v0
servers:
- url: http://localhost:8080
description: Generated server url
paths:
/container:
get:
tags:
- hello-controller
operationId: listElements
responses:
"200":
description: OK
content:
'*/*':
schema:
$ref: '#/components/schemas/ContainerClass'
components:
schemas:
ChildA:
type: object
description: ' Child A'
allOf:
- $ref: '#/components/schemas/ParentClass'
ChildB:
type: object
description: ' Child B'
allOf:
- $ref: '#/components/schemas/ParentClass'
ContainerClass:
type: object
properties:
elements:
type: array
description: array schema description
items:
oneOf:
- $ref: '#/components/schemas/ChildA'
- $ref: '#/components/schemas/ChildB'
ParentClass:
type: object
properties:
classType:
type: string
description: Parent description
discriminator:
propertyName: classType
mapping:
CHILD_A: '#/components/schemas/ChildA'
CHILD_B: '#/components/schemas/ChildB'
Actually, in my context, in order to have not any breaking change with existing consumers, I need items property in ContainerClass schema to contain the discriminator part that is contained in ParentClass schema, like this:
ContainerClass:
type: object
properties:
elements:
type: array
description: array schema description
items:
discriminator:
propertyName: classType
mapping:
CHILD_A: '#/components/schemas/ChildA'
CHILD_B: '#/components/schemas/ChildB'
oneOf:
- $ref: '#/components/schemas/ChildA'
- $ref: '#/components/schemas/ChildB'
When I try to set properties in annotation, I don't manage to do that. And when I debug code of io.swagger.v3.core.jackson.ModelResolver, I don't manage to find a way to do that. And so far I have not found an example of code that help me.
Is there a way so that a ComposedSchema (array contained in ContainerClass in my case) has a disciminator part generated by springdoc-openapi-maven-plugin execution?
This the default generation structure. Handled directly by swagger-api (and not springdoc-openapi.
The generated OpenAPI description looks coorect.
With springdoc-openapi, you can define an OpenApiCustomiser Bean, where you can change the elements of the components element defined on the OpenAPI level: