英文:
Spring Boot Swagger duplicate model type when using inheritance
问题
我有一个使用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"
}]
}
}
英文:
I've a Java project that uses Spring Boot and Swagger. The project consists of a simple API controller that implements a single endpoint. Invoking the GET
method on the endpoint gets all users. Invoking the PUT
method on the same endpoint updates a single user:
@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;
}
}
The /api/v1/users
endpoint is implemented using a BaseUser
which has subtypes like 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);
}
}
With this structure, when I browse the Swagger UI I see duplicates of these model types (based on the definitions in the OpenAPI spec).
I expected to see only a single BaseUser
and a single EmployeeUser
. What is the reason for the duplicates?
Definitions from OpenAPI Spec:
"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"
}]
}
}
答案1
得分: 2
我在版本3.0.0中遇到了类似的问题和其他问题,所以我仍然在我的项目中使用2.9.2版本。您可以尝试以下替代方法。
在测试项目中更改依赖项(移除springfox-bean-validators
,springfox-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 { }
...Swagger UI端点将位于http://localhost:8080/swagger-ui.html
,并返回您期望的类:
此外,您可以移除spring-core
依赖,因为它已经包含在spring-boot-starter-web
中,还可以移除maven-compiler-plugin
依赖,因为它是一个插件,并且可以移除重复的Maven编译器源代码和目标定义,这些定义已经作为属性定义了一次,并且作为Maven编译器插件的配置定义了第二次。
英文:
I've had a similar and other problems with version 3.0.0., so I still use 2.9.2 in my projects. You can try the following as an alternative.
When changing dependencies (removed springfox-bean-validators
, springfox-boot-starter
) in your test project to:
<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>
... and changing SwaggerConfig
(removing missing imports after changed dependencies) to:
@Configuration
@EnableSwagger2
public class SwaggerConfig { }
... the Swagger UI endpoint at http://localhost:8080/swagger-ui.html
will return classes you expect:
Also, you can remove spring-core
dependecy since it is already packed within the spring-boot-starter-web
, maven-compiler-plugin
dependency since it is a plugin, and remove duplicated maven compiler source and target definitions that are defined as properties and a second time as a configuration of the maven compiler plugin.
答案2
得分: 2
BaseUserReq、BaseUserRes、EmployeeUserReq和EmployeeUserRes是由于Springfox 3.0默认使用Swagger v3模型而生成的。您可以在application.properties中禁用它。
> Springfox 3.0默认使用v3模型。为了暂时解决这个问题,
> 在application.properties中添加:springfox.documentation.swagger.v2.use-model-v3=false。
> 来自https://github.com/springfox/springfox/issues/3503#issuecomment-684819445
在禁用了springfox v3模型后,我得到了:
这个问题在这里有描述:像“_1”这样带有数字的后缀被添加到重复的对象名称
> 嗨,@pitzcarraldo。感谢您的报告。
>
> 最近合并到主分支的更改,已在3.0.0-SNAPSHOT版本中提供,其意图是区分具有非对称属性的模型。
> 因此,如果模型在序列化和反序列化时具有不同的属性,SpringFox将生成两个模型。
> 用于序列化的“ModelName”和用于反序列化的“ModelName_1”,反之亦然。
> 来自https://github.com/springfox/springfox/issues/3014#issuecomment-497941639
我通过移除BaseUser
和EmployeeUser
构造函数中的@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
英文:
BaseUserReq, BaseUserRes, EmployeeUserReq and EmployeeUserRes are generated because Springfox 3.0 uses Swagger v3 models by default. You can disable it in application.properties.
> Springfox 3.0 uses v3 models by default. To workaround it for now,
> add: springfox.documentation.swagger.v2.use-model-v3=false in your
> application.properties.
> from https://github.com/springfox/springfox/issues/3503#issuecomment-684819445
After disabling springfox v3 models I got :
This issue is described here Suffix with number like "_1" is added to duplicated object name
> Hi, @pitzcarraldo. Thanks for the report.
>
> The intention for the last changes, that've been merged to master, and
> became available in the 3.0.0-SNAPSHOT version is to differ model with
> not symmetric properties. So if model has different properties for
> serialization and deserialization SpringFox will generate two models.
> "ModelName" for serialization and "ModelName_1" for deserialization or
> vise versa.
> from https://github.com/springfox/springfox/issues/3014#issuecomment-497941639
I fixed it by removing @JsonCreator
and @JsonProperty
in BaseUser
and EmployeeUser
constructors
As of springfox 3.0.0 swagger url is http://localhost:8080/swagger-ui/
See github repository https://github.com/ielatif/swagger-test
Commits history for explanations https://github.com/ielatif/swagger-test/commits/master
答案3
得分: 0
继承对我有用,但是如果我在模型中添加任何额外的方法(或者也许只是以 setXXX、getXXX 和 isXXX 命名的方法),在我的项目中就会出现这种情况。
如果我将我的模型制作成简单的 Java Bean,只包含设置器和获取器,没有其他逻辑,它会生成一个没有 Res 或 Req 后缀的单一模式对象。
英文:
Inheritance works for me, but this happens in my project if I add any extra methods to the models (or maybe it's just methods named setXXX, getXXX and isXXX).
If I make my models simple Java beans with just setters and getters and no other logic, it makes a single schema object without Res or Req suffixes.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论