gpt4 book ai didi

java - 使用外部枚举定义从 JAX-RS 端点生成 Swagger

转载 作者:搜寻专家 更新时间:2023-10-30 21:10:31 26 4
gpt4 key购买 nike

我想从具有外部枚举定义的 JAX-RS 端点生成 swagger,但是生成的 swagger 直接将枚举包含到模型的定义中。这意味着没有生成枚举文档,而且在客户端复制了相同的枚举。

我使用 swagger-jaxrs 依赖项来扫描我的端点并生成 swagger json 文件。这个 GitHub repository可用于重现问题。我还创建了一个 GitHub issue在 swagger-core 存储库上。

JAX-RS 端点

@Api("hello")
@Path("/helloSwagger")
public class HelloSwagger {

@ApiOperation(value = "Get all unique customers", notes = "Get all customers matching the given search string.", responseContainer = "Set", response = User.class)
@GET
@Path("/getUniqueUsers")
@Produces(MediaType.APPLICATION_JSON)
public Set<User> getUniqueUsers(
@ApiParam(value = "The search string is used to find customer by their name. Not case sensitive.") @QueryParam("search") String searchString,
@ApiParam(value = "Limits the size of the result set", defaultValue = "50") @QueryParam("limit") int limit
) {
return new HashSet<>(Arrays.asList(new User(), new User()));
}

}

带有枚举的模型

public class User {

private String name = "unknown";
private SynchronizationStatus ldap1 = SynchronizationStatus.UNKNOWN;
private SynchronizationStatus ldap2 = SynchronizationStatus.OFFLINE;

@ApiModelProperty(value = "The user name")
public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@ApiModelProperty(value = "The synchronization status with the LDAP1")
public SynchronizationStatus getLdap1() {
return ldap1;
}

public void setLdap1(SynchronizationStatus ldap1) {
this.ldap1 = ldap1;
}

public SynchronizationStatus getLdap2() {
return ldap2;
}

public void setLdap2(SynchronizationStatus ldap2) {
this.ldap2 = ldap2;
}
}

@ApiModel("The synchronization status with LDAP instance.")
public enum SynchronizationStatus {

UNKNOWN,
SYNC,
OFFLINE,
CONFLICT
}

生成的 swagger 的摘录

{
(...)
},
"definitions" : {
"User" : {
"type" : "object",
"properties" : {
"name" : {
"type" : "string",
"description" : "The user name"
},
"ldap1" : {
"type" : "string",
"description" : "The synchronization status with the LDAP1",
"enum" : [ "UNKNOWN", "SYNC", "OFFLINE", "CONFLICT" ]
},
"ldap2" : {
"type" : "string",
"enum" : [ "UNKNOWN", "SYNC", "OFFLINE", "CONFLICT" ]
}
}
}
}
}

预期结果

{
(...)
"definitions" : {
"SynchronizationStatus" : {
"description" : "The synchronization status with LDAP instance.",
"enum" : [ "UNKNOWN", "SYNC", "OFFLINE", "CONFLICT" ],
"type" : "string"
},
"User" : {
"type" : "object",
"properties" : {
"name" : {
"type" : "string",
"description" : "The user name"
},
"ldap1" : {
"$ref" : "#/definitions/SynchronizationStatus"
},
"ldap2" : {
"$ref" : "#/definitions/SynchronizationStatus"
}
}
}
}
}

我做错了什么还是 swagger-jaxrs 库的“功能”?

谢谢你的帮助

最佳答案

Am I doing something wrong or is it a 'feature' of the swagger-jaxrslibrary ?

枚举值被 swagger 视为原始值类型,开箱即用的 swagger 不会为枚举类型生成模型定义(see code 下的第 209 行)。所以这是一个特性,与 swagger-jaxrs 无关。

但是,您可以根据您的期望,通过提供自定义模型转换器 (io.swagger.converter.ModelConverter) 来生成 swagger 定义。

但在我看来,在 swagger 中开箱即用是一个不错的功能。

以下是一个 ruff 实现,可以帮助您生成预期的 swagger 定义。

package nhenneaux.test.swagger.ext;

import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.Iterator;
import java.util.List;

import com.fasterxml.jackson.databind.JavaType;

import io.swagger.annotations.ApiModel;
import io.swagger.converter.ModelConverter;
import io.swagger.converter.ModelConverterContext;
import io.swagger.jackson.ModelResolver;
import io.swagger.models.Model;
import io.swagger.models.ModelImpl;
import io.swagger.models.properties.Property;
import io.swagger.models.properties.RefProperty;
import io.swagger.models.properties.StringProperty;
import io.swagger.util.Json;

public class EnumAsModelAwareResolver extends ModelResolver {
static final EnumAsModelAwareResolver INSTANCE = new EnumAsModelAwareResolver();

public EnumAsModelAwareResolver() {
super(Json.mapper());
}

@Override
public Property resolveProperty(Type type, ModelConverterContext context, Annotation[] annotations,
Iterator<ModelConverter> chain) {
if (isEnumAnApiModel(type)) {
String name = findName(type);
// ask context to resolver enum type (for adding model definition
// for enum under definitions section
context.resolve(type);

return new RefProperty(name);
}
return chain.next().resolveProperty(type, context, annotations, chain);
}

private String findName(Type type) {
JavaType javaType = _mapper.constructType(type);
Class<?> rawClass = javaType.getRawClass();
ApiModel annotation = rawClass.getAnnotation(ApiModel.class);
String name = annotation.value();
if (name == null || name.length() == 0) {
name = rawClass.getSimpleName();
}
return name;
}

private boolean isEnumAnApiModel(Type type) {
JavaType javaType = _mapper.constructType(type);
return javaType.isEnumType()
&& javaType.getRawClass().isAnnotationPresent(ApiModel.class);
}

@Override
public Model resolve(Type type, ModelConverterContext context, Iterator<ModelConverter> chain) {
JavaType javaType = Json.mapper().constructType(type);
if (javaType.isEnumType()) {
ModelImpl model = new ModelImpl();
Class<?> rawClass = javaType.getRawClass();
ApiModel annotation = rawClass.getAnnotation(ApiModel.class);
String name = annotation.value();
if (name == null || name.length() == 0) {
name = rawClass.getSimpleName();
}
model.setName(name);
model.setDescription(annotation.description());
model.setType(StringProperty.TYPE);

List<String> constants = findEnumConstants(rawClass);
model.setEnum(constants);
return model;
}
return chain.next().resolve(type, context, chain);
}

private List<String> findEnumConstants(Class<?> rawClass) {
StringProperty p = new StringProperty();
_addEnumProps(rawClass, p);
return p.getEnum();
}

}

package nhenneaux.test.swagger.ext;

import io.swagger.converter.ModelConverters;
import io.swagger.jaxrs.config.BeanConfig;
import nhenneaux.test.swagger.ext.EnumAsModelAwareResolver;

public class EnumModelAwareBeanConfig extends BeanConfig {
public EnumModelAwareBeanConfig() {
registerResolver();
}

private void registerResolver() {
ModelConverters modelConverters = ModelConverters.getInstance();
// remove and add; in case it is called multiple times.
// should find a better way to register this.
modelConverters.removeConverter(EnumAsModelAwareResolver.INSTANCE);
modelConverters.addConverter(EnumAsModelAwareResolver.INSTANCE);
}

}

在你的测试中使用:

final BeanConfig beanConfig = new nhenneaux.test.endpoint.model.EnumModelAwareBeanConfig();

希望这有帮助。

关于java - 使用外部枚举定义从 JAX-RS 端点生成 Swagger,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42157941/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com