TNG / ArchUnit

A Java architecture test library, to specify and assert architecture rules in plain Java
http://archunit.org
Apache License 2.0
3.23k stars 298 forks source link

JavaClass.Predicates API: missing .extends(String/class/DescribedPredicate) #1169

Open u3r opened 1 year ago

u3r commented 1 year ago

I am trying to write a test that verifies that classes that are inherited from fulfill certain properties. However currently there is only JavaClass.Predicates.implement for interfaces, JavaClass.Predicates.assigneableTo/From and the latter do also return themselves if matching.

Stupid example demonstrating the problem - this matches each class ending in "FOO" with itself:

@ArchTest
   public ArchRule thisSadlyMatchesAllClassesEndingWithFOO  =
         noClasses()
               .that().haveSimpleNameEndingWith( "FOO" )
               .should( ArchCondition.from( JavaClass.Predicates.assignableTo( JavaClass.Predicates.simpleNameContaining( "FOO" ) ) ) );

My current custom predicate uses this logic:

 @Override 
      public boolean test( JavaClass javaClass ) { // Could be added as JavaClass.Predicates.extends
         return Stream.concat(
                     // leave out javaclass.this which is contained in javaClass.getClassHierarchy()
                     javaClass.getAllRawSuperclasses().stream(),
                     javaClass.getAllRawInterfaces().stream()
               )
               .anyMatch( innerPredicate );
      }

Is there a better way to do it? I've not put up a PR, as I didn't know what to do about performance and memoization of the classHierarchy.

codecholeric commented 10 months ago

Sorry for the late reply! I don't think there is any better way right now. I guess a strict extends vs assignableTo could make sense 🤔 What's your concrete use case where you need this?

u3r commented 10 months ago

I usually use ArchUnit to test for dangerous or unwanted API use ;) In this concrete case I actually test JUnit testcases for some parallelization edge cases that are QUITE hard to find otherwise: No (UnitTest)classes should extend classes that define a @BeforeAll method and don't ... \<some custom matching logic> And if I use the assignableTo it obviously fails on most UnitTests defining a @BeforeAll as it includes this

I had this case on other occasions where I want to express don't do this strange stuff to OTHER classes/classes you inherit from - doing it to yourself is fine

Does that help?

tupputis commented 4 weeks ago

Hi, is the extends predicate going to be introduced at some point, or anything equivalent? I have such false positives issue arising from pretty the same circumstance: assignableTo including this into the rule breakers. Hope this is planned to be available too! Cheers