首页 > 解决方案 > Swagger 注释别名不会生成正确的 OpenAPI

问题描述

我创建了以下别名:

@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)

才不是。怎么来的?

标签: javaannotationsswagger

解决方案


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

不幸的是,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
    }

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

更新:工作解决方案

正如我之前提到的,允许创建自定义 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


推荐阅读