Search code examples
archunit

ArchUnit: how to check for extension of an interface?


I have a package for which I want to check that all classes (these are entities that can get shipped over the net) do indeed implement the interface "java.io.Serializable". So I defined myself a rule like so (the actual rule has a few excludes but these are not relevant here):

@ArchTest
void checkSerializability(JavaClasses classes) {
    ArchRule rule = ArchRuleDefinition.classes()
        .that().resideInAnyPackage("..entities..")
        .should().implement(Serializable.class)
        ;
    rule.check(classes);
}

That rule works fine, except that a few classes implement a common interface that extends Serializable, i.e.:

interface IAction extends Serializable {
    ... some methods to be implemented declared here ...
}

The above ArchUnit-rule complains that this interface(-class) does not implement Serializable. In a sense that is true - strictly speaking it doesn't implement it, it just extends it.

But I didn't find an extends(<class>)-method, so I can not phrase this condition as implements(Serializable.class).or().extends(Serializable.class).

So, how can can I teach ArchUnit to accept that interface as "implementing" Serializable and hence as valid?


Solution

  • Let me cite the JavaDoc: ClassesShould.implement asserts that classes implement a certain interface. Note that this only matches non-interface classes that implement the supplied interface type (compare JavaClass.Predicates.implement(Class)). For general assignability see beAssignableTo, which in turn asserts that classes are assignable to a certain type (compare Class.isAssignableFrom(Class) terminology). A simple example for this predicate would be:

       assignableTo(Object.class).test(importedStringClass); // → returns true
       assignableTo(String.class).test(importedStringClass); // → returns true
       assignableTo(List.class).test(importedStringClass);   // → returns false
    

    So you can use

        ArchRule rule = ArchRuleDefinition.classes()
            .that().resideInAnyPackage("..entities..")
            .should().beAssignableTo(Serializable.class);