如何使用archunit验证方法注释是否使用具有特定值的属性

我有一个@Audit注释,它有许多可选属性,我需要useAccount = true对某些包强制使用一个布尔属性。


我正在尝试使用 archunit 来完成此验证,这样每当开发人员提交违反规则的代码时,CI 就会破坏并通知团队。


这会破坏构建:


@Audit

public myMethod(...) {

...

}

这是正确的方法:


@Audit(useAccount = true)

public myMethod(...) {

...

}

问题是 Archunit 目前不支持对方法进行断言。我期待做类似的事情:


methods().that().resideInAnyPackage("..controllers..", "..service..").and().areAnnotatedWith(Audit.class).should(attributeCheckCondition)

然后我的自定义条件attributeCheckCondition将负责查看属性值。


当我们检索类时,有没有办法检索方法?无需编写更复杂的谓词和条件?


holdtom
浏览 117回答 3
3回答

偶然的你

更新从 ArchUnit 0.10.0 开始,可以为成员创建规则。methods().that().areDeclaredInClassesThat().resideInAnyPackage("..controllers..", "..service..").and().areAnnotatedWith(Audit.class).should(attributeCheckCondition)另请参阅用户指南中的编写成员规则。原始答案由于目前没有可用于方法的基本规则定义,因此需要一个中间步骤。ArchUnitClassesTransformer可以将 JavaClasses 转换为其他类型的集合。ClassesTransformer<JavaMethod> methods = new AbstractClassesTransformer<JavaMethod>("methods") {&nbsp; &nbsp; @Override&nbsp; &nbsp; public Iterable<JavaMethod> doTransform(JavaClasses javaClasses) {&nbsp; &nbsp; &nbsp; &nbsp; Set<JavaMethod> allMethods = new HashSet<>();&nbsp; &nbsp; &nbsp; &nbsp; for (JavaClass javaClass : javaClasses) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; allMethods.addAll(javaClass.getMethods());&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return allMethods;&nbsp; &nbsp; }};然后ClassesTransformer可以将其用作自定义规则定义的基础。ArchRule rule = ArchRuleDefinition.all(methods).that(owner(resideInAnyPackage("..controllers..", "..service.."))).and(annotatedWith(Audit.class)).should(haveAttributeValue());rule.check(javaClasses);另请参阅用户指南中的自定义概念规则和本期。

凤凰求蛊

这是除了@raspacorp(启发了我!)之外的另一个自定义示例。为了检查@Secured(ROLE)方法注释,我实现了以下规则:public static class SecuredByRoleArchCondition extends ArchCondition<JavaMethod> {&nbsp; &nbsp; private final String[] expectedRoles;&nbsp; &nbsp; public SecuredByRoleArchCondition(String[] expectedRoles) {&nbsp; &nbsp; &nbsp; &nbsp; super(String.format("accessed by @Secured methods with roles %s", Arrays.toString(expectedRoles)));&nbsp; &nbsp; &nbsp; &nbsp; this.expectedRoles = expectedRoles;&nbsp; &nbsp; }&nbsp; &nbsp; public static SecuredByRoleArchCondition haveSecuredAnnotationWithRoles(String... expectedRoles) {&nbsp; &nbsp; &nbsp; &nbsp; return new SecuredByRoleArchCondition(expectedRoles);&nbsp; &nbsp; }&nbsp; &nbsp; @Override&nbsp; &nbsp; public void check(JavaMethod javaMethod, ConditionEvents events) {&nbsp; &nbsp; &nbsp; &nbsp; if (!javaMethod.isAnnotatedWith(Secured.class)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; String message = String.format("Method %s annotation @Secured(%s) is missing",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; javaMethod.getFullName(), Arrays.toString(expectedRoles));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; events.add(SimpleConditionEvent.violated(javaMethod, message));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; String[] annotationRoleValues = javaMethod.getAnnotationOfType(Secured.class).value();&nbsp; &nbsp; &nbsp; &nbsp; if (!Arrays.equals(annotationRoleValues, expectedRoles)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; String message = String.format("Method %s @Secured with %s has wrong roles, expected %s instead",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; javaMethod.getFullName(), Arrays.toString(annotationRoleValues), Arrays.toString(expectedRoles));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; events.add(SimpleConditionEvent.violated(javaMethod, message));&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}这是此 archCondition 的示例用法:@ArchTeststatic ArchRule admin_actions_with_post_mapping_should_be_secured_by_ADMIN_WRITE_role =&nbsp; &nbsp; &nbsp; &nbsp; methods()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .that().areDeclaredInClassesThat().resideInAnyPackage(ADMIN_PACKAGES)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .and().areAnnotatedWith(PostMapping.class)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .should(haveSecuredAnnotationWithRoles("ADMIN_WRITE"));

开满天机

我找到了一种在类上使用自定义谓词和条件的方法,当我这样做时,我没有意识到 Roland 的响应似乎更好,因为它提供了一种从方法角度表达规则断言的方法,这就是为什么我要求。但是我想在这里发布解决方案,以便对其他人有用。DescribedPredicate<JavaClass> HAVE_A_METHOD_ANNOTATED_WITH_AUDIT =&nbsp; &nbsp; new DescribedPredicate<JavaClass>("have a method annotated with @Audit")&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; @Override&nbsp; &nbsp; &nbsp; &nbsp; public boolean apply(JavaClass input)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return input.getMethods().stream().anyMatch(method -> method.isAnnotatedWith(Audit.class));&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; };ArchCondition<JavaClass> ONLY_SET_ATTRIBUTE_USE_ACCOUNT_SET_TO_TRUE =&nbsp; &nbsp; new ArchCondition<JavaClass>("only set useAccount attribute to true")&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; @Override&nbsp; &nbsp; &nbsp; &nbsp; public void check(JavaClass item, ConditionEvents events)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; item.getMethods().stream().filter(method ->&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;method.isAnnotatedWith(Audit.class) && !method.getAnnotationOfType(Audit.class)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .useAccount()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; )&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .forEach(method -> {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; String message = String.format(&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "Method %s is annotated with @Audit but useAccount is not set to true",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; method.getFullName());&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; events.add(SimpleConditionEvent.violated(method, message));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; };那么规则表示为:ArchRule ANNOTATION_RULE = classes()&nbsp; &nbsp; .that()&nbsp; &nbsp; .resideInAnyPackage("..controller..", "..service..")&nbsp; &nbsp; .and(HAVE_A_METHOD_ANNOTATED_WITH_AUDIT)&nbsp; &nbsp; .should(ONLY_SET_ATTRIBUTE_USE_ACCOUNT_SET_TO_TRUE);
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java