Swagger注释别名无法生成正确的OpenAPI

时间:2019-12-24 18:18:05

标签: java annotations swagger

我创建了以下别名:

@Retention(RetentionPolicy.RUNTIME)
@Parameter(in = ParameterIn.PATH,
           name = "FieldId",
           required = true,
           extensions = { @Extension(properties = @ExtensionProperty(name = "custom-type",
                                                                     value = "FieldId")) })
@AnnotationCollector
public @interface MyAnnotator {
}

在生成OpenAPI定义时,如果我直接在资源中使用@Parameter,则可以使用,但是如果使用@MyAnnotator,则将忽略它。例如:

@POST
@Consumes(MediaType.APPLICATION_JSON)
@Path("/{FieldId}")
void create(@Parameter(in = ParameterIn.PATH,
                        name = "FieldId",
                        required = true,
                        extensions = { @Extension(properties = @ExtensionProperty(name = "custom-type",
                                                                                 value = "FieldId")) },
                        schema = @Schema(type = "string")) final FieldId fieldId)

会生成

post:
  parameters:
  - name: FieldId
    in: path
    required: true
    schema:
      type: string
    x-custom-type: FieldId

但是做

@POST
@Consumes(MediaType.APPLICATION_JSON)
@Path("/{FieldId}")
void create(@MyAnnotator FieldId fieldId)

没有。怎么会来?

1 个答案:

答案 0 :(得分:3)

请参阅更新以获取有效的解决方案

不幸的是,swagger-core不支持此功能。 @Parameter批注必须直接放在参数上。

首先,JaxRS Reader实现会尝试查找并解析@Parameter注释,

io.swagger.v3.oas.annotations.Parameter paramAnnotation = AnnotationsUtils.getAnnotation(io.swagger.v3.oas.annotations.Parameter.class, paramAnnotations[i]);
Type paramType = ParameterProcessor.getParameterType(paramAnnotation, true);
if (paramType == null) {
    paramType = type;
} else {
    if (!(paramType instanceof Class)) {
        paramType = type;
    }
}
ResolvedParameter resolvedParameter = getParameters(paramType, Arrays.asList(paramAnnotations[i]), operation, classConsumes, methodConsumes, jsonViewAnnotation);

AnnotationUtils不再深入

public static <T> T getAnnotation(Class<T> cls, Annotation... annotations) {
    if (annotations == null) {
        return null;
    }
    for (Annotation annotation : annotations) {
        if (cls.isAssignableFrom(annotation.getClass())) {
            return (T)annotation;
        }
    }
    return null;
}

最后,getParameters(...)方法更严格。它检查注释的类型是否与所需的类型完全相同。

    for (Annotation annotation : annotations) {
        if (annotation instanceof QueryParam) {
            QueryParam param = (QueryParam) annotation;
            // ...
        } else if (annotation instanceof PathParam) {
            PathParam param = (PathParam) annotation;
            // ...
        } else if (annotation instanceof MatrixParam) {
            MatrixParam param = (MatrixParam) annotation;
            // ...
        }
        // ... and so on
    }

但是隧道尽头有一些光线。您可以创建实现OpenAPIExtension的自定义ParameterExtension服务,并可以处理这些自定义注释。

更新:有效的解决方案

正如我在创建自定义ParameterExtension服务之前所提到的那样。我做了一个最小的参数解析器扩展,扩展了DefaultParameterExtension

基本概念

所有参数模板都需要创建为自定义注释,如下所示:

@Retention(RetentionPolicy.RUNTIME)
@Parameter(in = ParameterIn.PATH,
        name = "FieldId",
        required = true,
        extensions = {@Extension(properties = @ExtensionProperty(name = "custom-type",
                value = "FieldId"))})
public @interface MyAnnotator {
}

扩展的ParameterExtension读取具有强制属性的@ParameterAlias注释。

@Path("/v1")
@Tags(@Tag(name = "test", description = ""))
public class FooResource {

    @PUT
    @Consumes(MediaType.APPLICATION_JSON)
    @Path("/{FieldId}")
    @Operation(operationId = "modifyFoo", summary = "Modifies a Foo entity")
    public void modify(@ParameterAlias(MyAnnotator.class) final FieldId fieldId) {

    }
}

最后,扩展扩展名ParameterAliasExtension处理@ParameterAliasExtension

public class ParameterAliasExtension extends DefaultParameterExtension {

    @Override
    public ResolvedParameter extractParameters(List<Annotation> annotations,
                                               Type type,
                                               Set<Type> typesToSkip,
                                               Components components,
                                               javax.ws.rs.Consumes classConsumes,
                                               javax.ws.rs.Consumes methodConsumes,
                                               boolean includeRequestBody,
                                               JsonView jsonViewAnnotation,
                                               Iterator<OpenAPIExtension> chain) {
        List<Annotation> extendedAnnotations = null;
        if (null != annotations) {
            extendedAnnotations = new ArrayList<>(annotations);
            ParameterAlias alias = AnnotationsUtils.getAnnotation(ParameterAlias.class, annotations.toArray(new Annotation[0]));
            if (null != alias) {
                Parameter aliasParameter = AnnotationsUtils.getAnnotation(Parameter.class, alias.value().getDeclaredAnnotations());
                if (null != aliasParameter) {
                    extendedAnnotations.add(aliasParameter);
                }
            }
        }
        return super.extractParameters(extendedAnnotations == null ? annotations : extendedAnnotations, 
                type, 
                typesToSkip, 
                components, 
                classConsumes, 
                methodConsumes, 
                includeRequestBody, 
                jsonViewAnnotation, 
                chain);
    }
}

此示例在我的GitHub存储库中可用:https://github.com/zforgo/stackoverflow/tree/master/openapi-alias