I want to write an archunit rule in my J2EE project to test when a class is annotated with @Startup, then it must contain a method that is annotated with @PostConstruct.
I tried this
@ArchTest
private val startUpBeansShouldHavePostConstruct: ArchRule = classes().that()
.areAnnotatedWith(Startup::class.java)
.shouldHave(methods().that().areAnnotatedWith(PostConstruct::class.java))
.because("classes with @Startup should contain a @PostConstruct annotated method")
but that doesn't compile in the shouldHave()-line. I am a bit stuck how to define such a rule. My actual goal is to have a rule that says there should be exactly one annotated method.
You can conveniently use ArchConditions.have
and DescribedPredicate.describe
to define custom conditions and predicates:
With
import com.tngtech.archunit.base.DescribedPredicate.describe
import com.tngtech.archunit.core.domain.JavaClass
import com.tngtech.archunit.junit.ArchTest
import com.tngtech.archunit.lang.conditions.ArchConditions.have
import com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes
you can use
@ArchTest
private val startUpBeansShouldHavePostConstruct =
classes()
.that().areAnnotatedWith(Startup::class.java)
.should(have(oneMethodAnnotatedWith(PostConstruct::class.java)))
private fun oneMethodAnnotatedWith(annotationClass: Class<out Annotation>) =
describe("one method annotated @${annotationClass.simpleName}") {
javaClass: JavaClass ->
javaClass.methods.count { it.isAnnotatedWith(annotationClass) } == 1
}