OpenApi - 有没有办法在用 springdoc-openapi-maven-plugin 生成的合同中有一个带有鉴别器部分的组合模式?
OpenApi - Is there a way to have a ComposedSchema with a discriminator part in a contract generated with springdoc-openapi-maven-plugin?
我有一个示例 SpringBoot API 具有以下功能:
- 1 个控制器,它公开一个可通过 GET 请求调用的端点,并且 returns 一个自定义 class(在我的示例中为 ContainerClass)
- ContainerClass 包含一个 属性 列表
- ParentClass 是一个抽象 class,它有 2 个子classes:ChildA 和 ChildB
我尝试使用 springdoc-openapi-maven-plugin.
从这个 API 生成一个 OpenApi 合约
在我的pom.xml中,我有以下元素:
- SpringBoot版本:2.2.6
- org.springdoc:springdoc-openapi-ui:1.4.1
- org.springdoc:springdoc-openapi-maven-plugin:1.0
这是我的 classes 我从中生成架构。
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{
}
当我运行springdoc-openapi-maven-plugin时,我得到如下合约文件
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'
实际上,在我的上下文中,为了不与现有消费者发生任何重大变化,我需要 items 属性 in ContainerClass 模式包含 鉴别器 部分,该部分包含在 ParentClass 模式中,如下所示:
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'
当我尝试在注释中设置属性时,我无法做到这一点。当我调试 io.swagger.v3.core.jackson.ModelResolver 的代码时,我无法找到一种方法来做到这一点。
到目前为止,我还没有找到对我有帮助的代码示例。
有没有办法让 ComposedSchema(在我的例子中包含在 ContainerClass 中的数组)有一个由 [= 生成的 disciminator 部分32=]springdoc-openapi-maven-plugin执行?
这是默认生成结构。由 swagger-api 直接处理(而不是 springdoc-openapi.
生成的 OpenAPI 描述看起来很正确。
使用springdoc-openapi,可以定义一个OpenApiCustomiser Bean,在这里可以更改定义在OpenAPI层面的components元素的元素:
这是我通过定义 OpenApiCustomiser Bean 的解决方案:
@Bean
public OpenApiCustomiser myCustomiser() {
Map<String, String> classTypeMapping = Map.ofEntries(
new AbstractMap.SimpleEntry<String, String>("CHILD_A", "#/components/schemas/ChildA"),
new AbstractMap.SimpleEntry<String, String>("CHILD_B", "#/components/schemas/ChildB")
);
Discriminator classTypeDiscriminator = new Discriminator().propertyName("classType")
.mapping(classTypeMapping);
return openApi -> openApi.getComponents().getSchemas().values()
.stream()
.filter(schema -> "ContainerClass".equals(schema.getName()))
.map(schema -> schema.getProperties().get("elements"))
.forEach(arraySchema -> ((ArraySchema)arraySchema).getItems().discriminator(classTypeDiscriminator));
}
我在合同文件中得到了预期的结果。
我有一个示例 SpringBoot API 具有以下功能:
- 1 个控制器,它公开一个可通过 GET 请求调用的端点,并且 returns 一个自定义 class(在我的示例中为 ContainerClass)
- ContainerClass 包含一个 属性 列表
- ParentClass 是一个抽象 class,它有 2 个子classes:ChildA 和 ChildB
我尝试使用 springdoc-openapi-maven-plugin.
从这个 API 生成一个 OpenApi 合约在我的pom.xml中,我有以下元素:
- SpringBoot版本:2.2.6
- org.springdoc:springdoc-openapi-ui:1.4.1
- org.springdoc:springdoc-openapi-maven-plugin:1.0
这是我的 classes 我从中生成架构。
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{
}
当我运行springdoc-openapi-maven-plugin时,我得到如下合约文件
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'
实际上,在我的上下文中,为了不与现有消费者发生任何重大变化,我需要 items 属性 in ContainerClass 模式包含 鉴别器 部分,该部分包含在 ParentClass 模式中,如下所示:
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'
当我尝试在注释中设置属性时,我无法做到这一点。当我调试 io.swagger.v3.core.jackson.ModelResolver 的代码时,我无法找到一种方法来做到这一点。 到目前为止,我还没有找到对我有帮助的代码示例。
有没有办法让 ComposedSchema(在我的例子中包含在 ContainerClass 中的数组)有一个由 [= 生成的 disciminator 部分32=]springdoc-openapi-maven-plugin执行?
这是默认生成结构。由 swagger-api 直接处理(而不是 springdoc-openapi.
生成的 OpenAPI 描述看起来很正确。
使用springdoc-openapi,可以定义一个OpenApiCustomiser Bean,在这里可以更改定义在OpenAPI层面的components元素的元素:
这是我通过定义 OpenApiCustomiser Bean 的解决方案:
@Bean
public OpenApiCustomiser myCustomiser() {
Map<String, String> classTypeMapping = Map.ofEntries(
new AbstractMap.SimpleEntry<String, String>("CHILD_A", "#/components/schemas/ChildA"),
new AbstractMap.SimpleEntry<String, String>("CHILD_B", "#/components/schemas/ChildB")
);
Discriminator classTypeDiscriminator = new Discriminator().propertyName("classType")
.mapping(classTypeMapping);
return openApi -> openApi.getComponents().getSchemas().values()
.stream()
.filter(schema -> "ContainerClass".equals(schema.getName()))
.map(schema -> schema.getProperties().get("elements"))
.forEach(arraySchema -> ((ArraySchema)arraySchema).getItems().discriminator(classTypeDiscriminator));
}
我在合同文件中得到了预期的结果。