Java 在Spring的编译时用另一个注释替换注释?

Java 在Spring的编译时用另一个注释替换注释?,java,spring,reflection,annotations,spring-annotations,Java,Spring,Reflection,Annotations,Spring Annotations,我在控制器参数上使用了招摇注释。因此,我最终得到了类似于@ApiParam(name=“default name”,value=“这是一个默认值”)的注释。我认为这些都很冗长。我想把它改成类似于@Foo。我想知道是否有办法在编译时将@Foo替换为@ApiParam。此外,由于我使用Spring,所以我想我也必须考虑在春天的注释处理顺序。我的意思是,我不应该在斯威格或斯普林拿起它之后,用@Foo替换@ApiParam。有没有办法做到这一点 简单地说,我有相同的注释,使用了5次相同的参数。基本上,我

我在控制器参数上使用了招摇注释。因此,我最终得到了类似于
@ApiParam(name=“default name”,value=“这是一个默认值”)
的注释。我认为这些都很冗长。我想把它改成类似于
@Foo
。我想知道是否有办法在编译时将
@Foo
替换为
@ApiParam
。此外,由于我使用Spring,所以我想我也必须考虑在春天的注释处理顺序。我的意思是,我不应该在斯威格或斯普林拿起它之后,用
@Foo
替换
@ApiParam
。有没有办法做到这一点

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

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);
    }
}
我知道我必须展示我已经尝试过的东西,但我甚至不知道从哪里开始


此外,这个问题与招摇无关,它只是一个例子。我想在编译时用另一个注释替换一个注释,这样Spring获取的注释就不会是我在源代码中添加的注释,而是我已经替换的注释。

如果我理解您的要求,这在没有编译时注释处理的情况下是可能的。这并不漂亮,可能比它的价值更复杂,但这里有一种方法可以做到这一点

这是我做的一个自定义注释,用于我的速记
@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
中定义要覆盖的任何属性。然后,可以使用为新注释实现自定义处理程序

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 Swigger的人不会熟悉


希望有帮助!祝你好运

您可以查看“Java注释处理器”,了解如何实现编译时注释处理。Spring注释处理发生在运行时,所以您的注释处理肯定会首先发生。你的例子没有说明你为什么要这样做。一个更具体的例子可以帮助别人提供建议。谢谢你的评论。我的例子中哪一部分不清楚?请你解释一下,这样我也可以提一下丢失的部分;不过,我认为我已经很好地解释了这个问题。没问题!您提到用完整的ApiParam交换Foo,但每个ApiParam都有不同的名称和值。每个ApiParam都有自己的速记符号吗?或者你打算对所有这些都使用Foo?一个ApiParam出现在多个地方吗?@jeff补充道,希望现在清楚了。它成功了!!!但为什么你认为它会增加另一个层次的复杂性呢?因为我实际上认为,将带有长参数的注释更改为直观的注释更有帮助。这是我的想法。你能解释一下你为什么这么想吗?另外,您的解决方案确实以一种惊人的方式解决了我的问题,但回到我的一般化问题,如何在编译时用另一个注释替换注释呢。我在你的第一条评论中搜索了你的建议,但我只找到了验证类的东西。太好了!我完全同意较小的注释在方法签名中更好。我确实理解这种愿望。但是这是一个定制的东西,只有您的项目与其他Springfox项目相比才会有。当其他开发人员第一次遇到这种情况时,他们必须弄清楚它是如何工作的,以及在出现问题时如何扩展或修复它。有一些编译器注释处理器允许您使用编译保留策略操作注释。我以前没做过,所以我不能给你更多。我还发现了其他SO问题,他们使用“字节码生成”动态添加注释,例如。这里有一篇关于如何编写编译器注释处理器的文章,我理解,但由于这是一个小项目,我认为值得一试:)。谢谢你的帮助,我真的很感激。