【问题标题】:Spring Boot Swagger duplicate model type when using inheritanceSpring Boot Swagger 使用继承时重复模型类型
【发布时间】:2021-01-11 14:52:02
【问题描述】:

我有一个使用 Spring Boot 和 Swagger 的 Java 项目。该项目由一个实现单个端点的简单 API 控制器组成。在端点上调用GET 方法获取所有用户。在同一端点上调用 PUT 方法会更新单个用户:

@RestController
@RequestMapping("/api/v1/users")
public class UserController {
    @RequestMapping(value = "", method = RequestMethod.GET)
    public List<BaseUser> getUsers(String name) {
        return null;
    }

    @RequestMapping(value = "", method = RequestMethod.PUT)
    public BaseUser updateUser(@RequestBody BaseUser user) {
        return null;
    }
}

/api/v1/users 端点是使用 BaseUser 实现的,它具有像 EmployeeUser 这样的子类型:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes({
        @JsonSubTypes.Type(value = EmployeeUser.class, name = "employee")
})
public abstract class BaseUser {

    private final int id;
    private final String name;

    @JsonCreator
    protected BaseUser(
            @JsonProperty("id") int id,
            @JsonProperty("name") String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }
}
public class EmployeeUser extends BaseUser {
    public EmployeeUser(@JsonProperty("id") int id,
                     @JsonProperty("name") String name) {
        super(id, name);
    }
}

使用这种结构,当我浏览 Swagger UI 时,我会看到这些模型类型的重复项(基于 OpenAPI 规范中的定义)。

我预计只会看到一个 BaseUser 和一个 EmployeeUser。重复的原因是什么?

OpenAPI 规范中的定义:

"definitions": {
    "BaseUserReq": {
        "type": "object",
        "discriminator": "type",
        "properties": {
            "id": {
                "type": "integer",
                "format": "int32"
            },
            "name": {
                "type": "string"
            }
        },
        "title": "BaseUserReq"
    },
    "BaseUserRes": {
        "type": "object",
        "discriminator": "type",
        "properties": {
            "id": {
                "type": "integer",
                "format": "int32"
            },
            "name": {
                "type": "string"
            }
        },
        "title": "BaseUserRes"
    },
    "EmployeeUserReq": {
        "title": "EmployeeUser",
        "allOf": [{
            "$ref": "#/definitions/BaseUserReq"
        }, {
            "type": "object",
            "properties": {
                "id": {
                    "type": "integer",
                    "format": "int32"
                },
                "name": {
                    "type": "string"
                }
            },
            "title": "EmployeeUserReq"
        }]
    },
    "EmployeeUserRes": {
        "title": "EmployeeUser",
        "allOf": [{
            "$ref": "#/definitions/BaseUserRes"
        }, {
            "type": "object",
            "properties": {
                "id": {
                    "type": "integer",
                    "format": "int32"
                },
                "name": {
                    "type": "string"
                }
            },
            "title": "EmployeeUserRes"
        }]
    }
}

【问题讨论】:

  • BaseUserReq、BaseUserRes、EmployeeUserReq和EmployeeUserRes从何而来?
  • 我不知道,它来自 Swagger 工具——我的项目中不存在类型。
  • 你使用的是哪个版本的springfox依赖?
  • 它们是 3.0.0 版。我的测试 maven 项目在这里可用:filedropper.com/swagger-test
  • 请分享一个github repo,它比文件托管更方便

标签: java spring spring-boot swagger springfox


【解决方案1】:

我在使用 3.0.0 版本时遇到了类似的问题和其他问题,所以我仍然在我的项目中使用 2.9.2。您可以尝试以下方法。

将测试项目中的依赖项(已删除springfox-bean-validatorsspringfox-boot-starter)更改为:

<dependency>
   <groupId>io.springfox</groupId>
   <artifactId>springfox-swagger2</artifactId>
   <version>2.9.2</version>
</dependency>
<dependency>
   <groupId>io.springfox</groupId>
   <artifactId>springfox-swagger-ui</artifactId>
   <version>2.9.2</version>
</dependency>

...并将SwaggerConfig(在更改依赖项后删除缺少的导入)更改为:

@Configuration
@EnableSwagger2
public class SwaggerConfig { }

...http://localhost:8080/swagger-ui.html 的 Swagger UI 端点将返回您期望的类:


此外,您可以删除 spring-core 依赖项,因为它已经打包在 spring-boot-starter-webmaven-compiler-plugin 依赖项中,因为它是一个插件,并删除重复的 maven 编译器源和目标定义,它们定义为属性和第二个time 作为 maven 编译器插件的配置。

【讨论】:

    【解决方案2】:

    BaseUserReq、BaseUserRes、EmployeeUserReq 和 EmployeeUserRes 是因为 Springfox 3.0 默认使用 Swagger v3 模型而生成的。您可以在 application.properties 中禁用它。

    Springfox 3.0 默认使用 v3 模型。要暂时解决它, 添加:springfox.documentation.swagger.v2.use-model-v3=false 在您的 应用程序.properties。 来自https://github.com/springfox/springfox/issues/3503#issuecomment-684819445

    禁用 springfox v3 模型后,我得到了:

    这里描述了这个问题Suffix with number like "_1" is added to duplicated object name

    嗨,@pitzcarraldo。感谢您的报告。

    最后一次更改的意图,已合并到 master,以及 在 3.0.0-SNAPSHOT 版本中可用是与不同的模型 非对称性质。因此,如果模型具有不同的属性 序列化反序列化 SpringFox会生成两个模型。 “ModelName”用于序列化,“ModelName_1”用于反序列化或 反之亦然。 来自https://github.com/springfox/springfox/issues/3014#issuecomment-497941639

    我通过删除 BaseUserEmployeeUser 构造函数中的 @JsonCreator@JsonProperty 来修复它

    从 springfox 3.0.0 开始,swagger url 是 http://localhost:8080/swagger-ui/

    见github仓库https://github.com/ielatif/swagger-test

    提交历史解释https://github.com/ielatif/swagger-test/commits/master

    【讨论】:

    • 就我而言,我无法删除@JsonProperty,因为基类不在我的控制范围内。还有其他解决方法吗?
    【解决方案3】:

    继承对我有用,但是如果我向模型添加任何额外的方法(或者可能只是名为 setXXX、getXXX 和 isXXX 的方法),就会在我的项目中发生这种情况。

    如果我让我的模型成为简单的 Java bean,只有 setter 和 getter 而没有其他逻辑,它会生成一个没有 Res 或 Req 后缀的模式对象。

    【讨论】:

      猜你喜欢
      • 2020-03-14
      • 2019-09-02
      • 2011-08-17
      • 1970-01-01
      • 1970-01-01
      • 2020-01-18
      • 2011-08-19
      • 2020-05-01
      • 2022-10-07
      相关资源
      最近更新 更多