Как проверить, что аннотация метода использует атрибут с определенным значением, используя archunit - PullRequest
0 голосов
/ 02 февраля 2019

У меня есть @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 позаботится о поиске значения атрибута.

Есть ли способ получения методов при полученииклассы?Без необходимости писать более сложный предикат и условие?

Ответы [ 2 ]

0 голосов
/ 05 февраля 2019

Я нашел способ сделать это с помощью пользовательского предиката и условия над классами, когда я сделал это, я не знал об ответе Роланда, который кажется лучше, так как он предоставляет способ выразить утверждение правила с точки зрения методов, которыеВот почему я просил.

Однако я хотел опубликовать решение здесь, чтобы оно могло быть полезным для других.

DescribedPredicate<JavaClass> HAVE_A_METHOD_ANNOTATED_WITH_AUDIT =
    new DescribedPredicate<JavaClass>("have a method annotated with @Audit")
    {
        @Override
        public boolean apply(JavaClass input)
        {
            return input.getMethods().stream().anyMatch(method -> method.isAnnotatedWith(Audit.class));
        }
    };

ArchCondition<JavaClass> ONLY_SET_ATTRIBUTE_USE_ACCOUNT_SET_TO_TRUE =
    new ArchCondition<JavaClass>("only set useAccount attribute to true")
    {
        @Override
        public void check(JavaClass item, ConditionEvents events)
        {
            item.getMethods().stream().filter(method ->
           method.isAnnotatedWith(Audit.class) && !method.getAnnotationOfType(Audit.class)
                                                            .useAccount()
            )
                .forEach(method -> {
                    String message = String.format(
                        "Method %s is annotated with @Audit but useAccount is not set to true",
                        method.getFullName());
                    events.add(SimpleConditionEvent.violated(method, message));
                });
        }
    };

Тогда правило выражается как:

ArchRule ANNOTATION_RULE = classes()
    .that()
    .resideInAnyPackage("..controller..", "..service..")
    .and(HAVE_A_METHOD_ANNOTATED_WITH_AUDIT)
    .should(ONLY_SET_ATTRIBUTE_USE_ACCOUNT_SET_TO_TRUE);
0 голосов
/ 02 февраля 2019

Обновление

Начиная с ArchUnit 0.10.0, можно создавать правила для членов.

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

См. Также Составление правил для членов в Руководстве пользователя.

Оригинальный ответ

Поскольку в настоящее время нет базовых определений правил, доступных для методов, необходим промежуточный шаг.ArchUnit имеет ClassesTransformer для преобразования JavaClasses в коллекцию других типов.

ClassesTransformer<JavaMethod> methods = new AbstractClassesTransformer<JavaMethod>("methods") {
    @Override
    public Iterable<JavaMethod> doTransform(JavaClasses javaClasses) {
        Set<JavaMethod> allMethods = new HashSet<>();
        for (JavaClass javaClass : javaClasses) {
            allMethods.addAll(javaClass.getMethods());
        }
        return allMethods;
    }
};

Этот ClassesTransformer может затем использоваться в качестве основы для пользовательских определений правил.

ArchRule rule = ArchRuleDefinition.all(methods).that(owner(resideInAnyPackage("..controllers..", "..service.."))).and(annotatedWith(Audit.class)).should(haveAttributeValue());
rule.check(javaClasses);

См. Также Правила с пользовательскими понятиями в Руководстве пользователя и эту проблему .

...