当前位置: 首页 > 知识库问答 >
问题:

基于枚举值Swagger生成子类型

曹季同
2023-03-14

我有以下结构

             Notification
                  |
        ------------------------
        |                      |
  SmsNotification         EmailNotification

通知包含枚举notificationtype,该枚举包含短信电子邮件。现在我有了一个收件箱类,它包含一个通知

这是在swagger yml中指定的(删除了一些不相关的代码)

definitions:
  Notification:
    type: "object"
    discriminator: "notificationType"
    properties:
      notificationType:
        type: "string"
        description: "Type of notification"
        enum:
          - "EMAIL"
          - "SMS"

  SmsNotification:
    allOf:
      - $ref: "#/definitions/Notification"
      - type: "object"

  EmailNotification
    allOf:
      - $ref: "#/definitions/Notification"
      - type: "object"

  Inbox:
    type: "object"
    properties:
      notification:
        description: "Latest received notification"
        $ref: "#/definitions/Notification"

我使用swagger-codegenV2(也尝试了v3&openapi-generator)生成代码,配置如下:

<build>
  <plugins>
      <plugin>
          <groupId>io.swagger</groupId>
          <artifactId>swagger-codegen-maven-plugin</artifactId>
          <version>2.3.1</version>
          <executions>
              <execution>
                 <id>notifications</id>
                  <goals>
                      <goal>generate</goal>
                  </goals>
                  <configuration>
                      <inputSpec>${project.basedir}/src/main/notifications/swagger.yaml</inputSpec>
                      <language>java</language>
                      <library>jersey2</library>
                      <generateSupportingFiles>false</generateSupportingFiles>
                      <modelPackage>${generated.package}</modelPackage>
                      <generateApis>false</generateApis>
                      <generateApiDocumentation>false</generateApiDocumentation>
                      <generateModelTests>false</generateModelTests>
                      <generateModelDocumentation>false</generateModelDocumentation>
                  </configuration>
              </execution>
         </executions>
     </plugin>
  </plugins>
</build>

现在发生的情况是,jersey2库将生成JSONSubtype注释:

@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.Property, property="notificationType", visible=true)
@JsonSubTypes({
  @JsonSubTypes.Type(value=SmsNotification.class, name="SmsNotification"),
  @JsonSubTypes.Type(value=EmailNotification.class, name="EmailNotification")
})
public class Notification {
  ...
}

这里的问题是,如果我现在尝试反序列化/序列化包含带有notificationtype=email的收件箱的Json字符串,它将引发异常,因为没有名称为'email'的已知子类型。

seralizer期望jsonsubtype注释指定如下:(旁注,这也是生成swagger yaml的代码的外观)

@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.Property, property="notificationType", visible=true)
@JsonSubTypes({
  @JsonSubTypes.Type(value=SmsNotification.class, name="SMS"),
  @JsonSubTypes.Type(value=EmailNotification.class, name="EMAIL")
})
public class Notification {
  ...
}

有人知道如何根据需要生成jsonsubtypes注释而不是当前的行为吗?

共有1个答案

曹钊
2023-03-14

我有一个类似的问题,并修复了它。

我不直接维护OpenAPI定义,而是在bean中使用注释。然后生成OpenAPI定义(JSON格式),然后使用OpenAPI-Generator生成客户机项目。

问题来自缺少discriminatormapping注释。

Entity.java

@JsonTypeInfo(
    use = JsonTypeInfo.Id.NAME,
    include = JsonTypeInfo.As.EXISTING_PROPERTY,
    property = "type",
    visible = true
)
@JsonSubTypes({
    @JsonSubTypes.Type(value = FooEntity.class, name = "FOO"),
    @JsonSubTypes.Type(value = BarEntity.class, name = "BAR")
})
// Without the following annotations I have the same issue than OP
@Schema(
    description = "Entity",
    discriminatorProperty = "type",
    discriminatorMapping = {
        @DiscriminatorMapping(schema = FooEntity.class, value = "FOO"),
        @DiscriminatorMapping(schema = BarEntity.class, value = "BAR")
    }
)
public abstract class Entity {

    @Schema(description = "Entity type", required = true)
    protected final EntityType type;
}

EntityType.java

@Schema(description = "Entity type")
public enum EntityType {
    FOO,
    BAR
}

java(barentity.java的工作方式相同)。

@Schema(description = "Foo entity")
public class FooEntity extends Entity {

    public FooEntity() {
        super(EntityType.FOO);
    }
}
// ...
"schemas": {
    "Entity": {
        "required": [
            "type"
        ],
        "type": "object",
        "properties": {
            "type": {
                "type": "string",
                "enum": [
                    "FOO",
                    "BAR"
                ]
            }
        },
        "description": "Entity",
        "discriminator": {
            "propertyName": "type",
            "mapping": {
                "FOO": "#/components/schemas/FooEntity",
                "BAR": "#/components/schemas/BarEntity"
            }
        }
    },
    "FooEntity": {
        "required": [
            "type"
        ],
        "type": "object",
        "description": "Foo entity",
        "allOf": [
            {
                "$ref": "#/components/schemas/Entity"
            }
        ]
    },
}
// ...

在我的pom.xml中使用以下插件生成

<plugin>
    <groupId>io.swagger.core.v3</groupId>
    <artifactId>swagger-maven-plugin</artifactId>
    <version>2.1.2</version>
    <executions>
        <execution>
            <id>generate-api-definition</id>
            <phase>compile</phase>
            <goals>
                <goal>resolve</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <configurationFilePath>${project.build.directory}/api/WEB-INF/openapi-configuration.json</configurationFilePath> <!-- My configuration file -->
        <outputPath>${project.build.directory}/api/WEB-INF</outputPath>
        <outputFileName>openapi</outputFileName>
        <outputFormat>JSON</outputFormat>
    </configuration>
</plugin>
//...
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2020-05-07T15:17:15.844882+02:00[Europe/Paris]")
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type", visible = true)
@JsonSubTypes({
    @JsonSubTypes.Type(value = FooEntity.class, name = "FOO"),
    @JsonSubTypes.Type(value = BarEntity.class, name = "BAR")
})
public class Entity {

    public enum TypeEnum {
        FOO("FOO"),
        BAR("BAR");
        // ...
    }

    public static final String JSON_PROPERTY_TYPE = "type";
    protected TypeEnum type;

    public Entity type(TypeEnum type) {
        this.type = type;
        return this;
    }

    @ApiModelProperty(required = true, value = "Entity type")
    @JsonProperty(JSON_PROPERTY_TYPE)
    @JsonInclude(value = JsonInclude.Include.ALWAYS)

    public TypeEnum getType() {
        return type;
    }


    public void setType(TypeEnum type) {
        this.type = type;
    }
    // ...
}

生成器插件:

<plugin>
    <groupId>org.openapitools</groupId>
    <artifactId>openapi-generator-maven-plugin</artifactId>
    <version>4.3.1</version>
    <executions>
        <execution>
            <id>generate-client</id>
            <phase>generate-sources</phase>
            <goals>
                <goal>generate</goal>
            </goals>
            <configuration>
                <!-- https://github.com/OpenAPITools/openapi-generator/tree/master/modules/openapi-generator-maven-plugin -->
                <inputSpec>x/y/z/openapi.json</inputSpec>
                <addCompileSourceRoot>false</addCompileSourceRoot>
                <generatorName>java</generatorName>
                <configOptions>
                    <java8>true</java8>
                    <serializableModel>true</serializableModel>
                    <serializationLibrary>jackson</serializationLibrary>
                    <library>jersey2</library>
                    <dateLibrary>java8</dateLibrary>
                    <!-- ... -->
                </configOptions>
            </configuration>
        </execution>
    </executions>
</plugin>
 类似资料:
  • 我的api如下所示: 对于查询,我们只想允许查询枚举中列出的某些属性,如下所示: 我加了 在启动阶段。cs,但这不适用于默认值,我得到以下生成的虚张声势,默认值为0而不是字符串: 如何使默认值显示为字符串?

  • 问题内容: 假设我有一个格式为基本XML的文件,如下所示: 我想在运行时变成这样的东西: …,然后将新创建的枚举传递给我的应用程序。我将如何实现这样的目标?可以吗 问题答案: 您尝试做的事情没有任何意义。枚举实际上仅是为了编译时的利益,因为它们表示一组固定的常量。在运行时,动态生成的枚举的含义是什么- 与普通对象有什么不同?例如: 您的XML可以解析为新实例化的对象,这些对象可以存储在某些程序中,

  • 使用JAXB从XSD(作为标准分发,我无法控制,也无法更改)生成一些POJO有很多困难。问题似乎与XSD中定义某些类型的方式有关。下面我粘贴了一个在XSD中定义的名为TransactionCodeType的简单类型,它是一个令牌与值的枚举列表(也定义为令牌)的联合。 使用JAXB,生成的输出(见下文)被翻译为Java中的基本类型字符串。我使用的是来自org的最新版本的maven-jaxb2-plu

  • 我在BE端有属性,我可以通过处理程序获取和设置。我使用枚举来设置属性,并使用bean类来获取。现在我需要重复属性名称,我想避免它。 现在我必须支持这些类之间的两种方式的一致性。

  • 问题内容: 我有一个枚举的类对象(我有一个),我需要获取此枚举表示的枚举值的列表。该静态函数有我需要什么,但我不知道怎么去从类对象访问它。 问题答案:

  • 问题内容: 假设是,我将如何产生给定序数的枚举值? 问题答案: 足够了。一条线; 足够简单。