Swagger 注释别名不会生成正确的 OpenAPI

Swagger annotation alias does not generate proper 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)

没有。怎么会?

查看更新以获得有效的解决方案

很遗憾,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/Whosebug/tree/master/openapi-alias