javajunitjunit5junit-jupiterarchunit

How do I exclude an ArchUnit rule aiming at interface to impact @interface (annotation)


I would like to write an ArchUnit test which says:

"the classes that are interfaces should have a name ending with Interface, but not the @interface ones (they are annotations)".

For instance, this should be OK:

// Interface definition
interface AnimalInterface {
void animalSound(); // abstract method
void sleep(); // abstract method
}

But this should not

// Interface definition
interface Animal {
void animalSound(); // abstract method
void sleep(); // abstract method
}

But also (and this is the part I am having issues with):

import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Constraint(validatedBy = SomethingValidator.class)
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidSomething {
    String message() default "Invalid request data";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

Should not be taken into account in this test, since it is @interface, not interface.

I tried to achieve this by writing the following code:

@Test
void interfacesShouldHaveNamesEndingWithTheWordInterface() {
    classes().that().areInterfaces().should().haveNameMatching(".*Interface").check(importedClasses);
}

But this would fail for the @interface part.

How to enhance the test to "ignore" "filter out" annotations?


Solution

  • You can use the DescribedPredicate<JavaClass> JavaClass.Predicates.ANNOTATIONS, or the corresponding fluent API for ArchRules, to exclude annotations from your rule:

        @ArchTest
        ArchRule rule = classes()
                .that().areInterfaces()
                .and().areNotAnnotations()
                .should().haveNameMatching(".*Interface");