在 Spring 的编译期间用另一个注释替换一个注释?

Replacing an annotation with another annotation during compile time in Spring?

我在我的控制器参数上使用 Swagger 注释。所以,我最终得到了像 @ApiParam(name="default name", value="this is a default value") 这样的注释。我认为这很冗长。我想将其更改为 @Foo 之类的内容。我想知道是否有办法在编译期间用 @ApiParam 替换 @Foo 。另外,由于我使用的是 Spring,我想我也必须考虑 Spring 中的注释处理顺序。我的意思是我不应该在 Swagger 或 Spring 拿起它后用 @Foo 替换 @ApiParam 。有什么办法吗?

简而言之,我使用了 5 次具有相同参数的相同注释。基本上,我想用一些自定义注释替换它们。

我知道我必须展示我已经尝试过的东西,但我什至不知道从哪里开始。

另外,这个问题与Swagger无关,只是一个例子。我想在编译时用一个注解替换另一个注解,这样 Spring 选择的就不是我放在源代码上的那个,而是我替换的那个。

如果我理解您的要求,则无需编译时注释处理即可实现。它并不漂亮,而且可能比它的价值更复杂,但这是一种方法。

这是我为我的 shorthand @ApiParam 创建的自定义注释。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface GameIdParam {
    String name() default "My Game ID";

    String value() default "The integer ID of a particular game";
}

您可以在 @ApiParam 中定义您希望覆盖的任何属性。然后您可以使用 Springfox's Extension Framework 为新注释实现自定义处理程序。

import com.google.common.base.Optional;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import springfox.documentation.schema.Example;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.schema.EnumTypeDeterminer;
import springfox.documentation.spi.service.contexts.ParameterContext;
import springfox.documentation.spring.web.DescriptionResolver;
import springfox.documentation.swagger.readers.parameter.ApiParamParameterBuilder;

import java.util.function.Predicate;

import static java.util.Optional.ofNullable;
import static springfox.documentation.swagger.common.SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER;
import static springfox.documentation.swagger.common.SwaggerPluginSupport.pluginDoesApply;
import static springfox.documentation.swagger.readers.parameter.Examples.examples;

@Component
public class ShorthandAnnotationPlugin extends ApiParamParameterBuilder {
    private final DescriptionResolver descriptions;
    private final EnumTypeDeterminer enumTypeDeterminer;

    @Autowired
    public ShorthandAnnotationPlugin(
            DescriptionResolver descriptions,
            EnumTypeDeterminer enumTypeDeterminer) {
        super(descriptions, enumTypeDeterminer);
        this.descriptions = descriptions;
        this.enumTypeDeterminer = enumTypeDeterminer;
    }

    @Override
    public void apply(ParameterContext context) {
        Optional<GameIdParam> gameIdParam = context.resolvedMethodParameter().findAnnotation(GameIdParam.class);

        if (gameIdParam.isPresent()) {
            GameIdParam annotation = gameIdParam.get();

            // Instantiate an ApiParam so we can take default values for attributes we didn't override.
            ApiParam parentAnnotation = AnnotationUtils.synthesizeAnnotation(ApiParam.class);

            context.parameterBuilder().name(ofNullable(annotation.name())
                    .filter(((Predicate<String>) String::isEmpty).negate()).orElse(null))
                    .description(ofNullable(descriptions.resolve(annotation.value()))
                            .filter(((Predicate<String>) String::isEmpty).negate()).orElse(null))
                    .parameterAccess(ofNullable(parentAnnotation.access())
                            .filter(((Predicate<String>) String::isEmpty).negate())
                            .orElse(null))
                    .defaultValue(ofNullable(parentAnnotation.defaultValue())
                            .filter(((Predicate<String>) String::isEmpty).negate())
                            .orElse(null))
                    .allowMultiple(parentAnnotation.allowMultiple())
                    .allowEmptyValue(parentAnnotation.allowEmptyValue())
                    .required(parentAnnotation.required())
                    .scalarExample(new Example(parentAnnotation.example()))
                    .complexExamples(examples(parentAnnotation.examples()))
                    .hidden(parentAnnotation.hidden())
                    .collectionFormat(parentAnnotation.collectionFormat())
                    .order(SWAGGER_PLUGIN_ORDER);
        }
    }

    @Override
    public boolean supports(DocumentationType documentationType) {
        return pluginDoesApply(documentationType);
    }
}

我以Springfox's ApiParamParameterBuilder为例。

现在,我可以使用我的 @GameIdParam

@PostMapping("/{gameId}/info")
public String play(@GameIdParam @PathVariable int gameId) // ...

此模式可以推广以使用一系列自定义 shorthand 注释。它并不漂亮,它引入了另一种间接级别,了解 Springfox Swagger 的人不会熟悉它。

希望对您有所帮助!祝你好运!