【问题标题】:Can you require at least 1 Spring Annotation of a certain type on a method?你可以在一个方法上要求至少 1 个特定类型的 Spring Annotation 吗?
【发布时间】:2021-08-14 00:34:47
【问题描述】:

我们有两种类型的注解。一个指定 Authz 检查,另一个明确指定不进行:@AuthZCheck(type=...) 和 @NoAuthZCheck。

有没有办法要求方法上至少有一个注释,否则会导致某种(最好是)编译时错误?

// this is ok
@AuthZCheck
public void getSensitiveInfo()

// this is ok
@NoAuthZCheck
public void getPublicInfo()

// this is NOT ok
public void getInfo()

编辑1 澄清一下,这与其说是功能问题,不如说是政策问题。我们允许其他开发人员编写这些方法,我们希望他们仔细考虑它需要哪种类型的 AuthZ 检查。其中一些确实不需要 AuthZ 检查,因为它是一个公共 API,或者因为后端服务自己进行 AuthZ 验证。 但是我们发现开发人员不加考虑就忽略了 AuthZ 检查的情况。他们可能已经复制粘贴了另一种不需要它的方法,而没有考虑甚至不知道 AuthZ 检查功能。 我们想结束这种做法并要求一个明确的 AuthZ 注释,即使在不需要 AuthZ 时也是如此。

【问题讨论】:

  • 不确定编译时错误,但是对于运行时错误,构造函数可以通过反射获取所有方法上的所有注释,如果没有任何注释,或者需要的注释,抛出一个例外。或者检查注释的单元测试也可以协调这一点并产生构建错误
  • 运行时反射会影响性能。此代码位于我们的边缘网关中,因此如果可能,希望避免这种情况。单元测试是一个有趣的选项,但需要开发人员编写它
  • 您可以将当前的@AuthZCheck 行为设置为未注释方法的默认行为。
  • @tgdavies 我仍然需要一种方法来要求 AuthZCheck 以确保有人不会忘记它
  • 当你调用一个没有注解的方法时,只要 AuthZCheck 做任何事情。

标签: java spring annotations


【解决方案1】:

您可以通过注释来做到这一点 Processor。 样板实现如下。

package processing;

import java.util.Collections;
import java.util.Set;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedOptions;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.TypeElement;

public class CheckAuthZ implements Processor {
    private ProcessingEnvironment processingEnv = null;

    @Override
    public Set<String> getSupportedOptions() { return Collections.emptySet(); }

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        return Collections.singleton("*");
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        SourceVersion[] values = SourceVersion.values();

        return values[values.length - 1];
    }

    @Override
    public void init(ProcessingEnvironment processingEnv) {
        this.processingEnv = processingEnv;
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        /*
         * Called for every TypeElement
         */
    }
}

您需要充实process() 方法的逻辑。我已经迭代 通过并检查公共方法是否存在至少一个注释。

import ...AuthZCheck;
import ...NoAuthZCheck;

import static javax.lang.model.element.Modifier.PUBLIC;
import static javax.lang.model.util.ElementFilter.methodsIn;
import static javax.tools.Diagnostic.Kind.ERROR;

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        for (TypeElement type : set) {
            for (ExecutableElement method : methodsIn(type.getEnclosedElements())) {
                if (method.getModifiers().contains(PUBLIC)) {
                    if (! (method.getAnnotation(AuthZCheck.class) != null || method.getAnnotation(NoAuthZCheck.class) != null)) {
                        processingEnv.getMessager()
                            .printMessage(ERROR, "No annotation");
                    }
                }
            }
        }
    }

(如果要继续编译,请使用 WARNING 而不是 ERROR。)

并打包成一个JAR作为服务提供者。 META-INF/services/javax.annotation.processing.Processor 必须包含:

processing.CheckAuthZ

在编译路径中包含该 JAR 以进行强制/检测。

【讨论】:

    猜你喜欢
    • 2014-09-20
    • 2011-07-21
    • 2017-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多